def with_type_validation_False(context):
            context.memoize("type_validation", lambda self: False)

            @context.example
            def it_passes_with_invalid_types(self):
                self.target(message=1234)
def mock_constructor(context):

    context.memoize("target_module", lambda self: sys.modules[__name__])
    context.memoize_before("target_class_name", lambda self: target_class_name)

    @context.function
    def get_target_class(self):
        return getattr(self.target_module, self.target_class_name)

    @context.function
    @contextlib.contextmanager
    def assertRaisesWithMessageInException(self, exception, msg):
        with self.assertRaises(exception) as cm:
            yield
        ex_msg = str(cm.exception)
        self.assertIn(
            msg,
            ex_msg,
            "Expected exception {}.{} message "
            "to be\n{}\nbut got\n{}.".format(exception.__module__,
                                             exception.__name__, repr(msg),
                                             repr(ex_msg)),
        )

    @context.before
    def assert_unpatched(self):
        self.assertTrue(original_target_class is self.get_target_class(),
                        "Unpatching didn't work.")
        args = (1, 2)
        kwargs = {"3": 4, "5": 6}
        t = Target(*args, **kwargs)
        self.assertEqual(type(t), original_target_class)
        self.assertEqual(t.args, args)
        self.assertEqual(t.kwargs, kwargs)

    @context.shared_context
    def class_attributes(context):
        @context.example
        def attributes_are_not_affected(self):
            self.assertEqual(self.class_attribute_target.CLASS_ATTR,
                             "CLASS_ATTR")

        @context.example
        def static_methods_are_not_affected(self):
            self.assertEqual(self.class_attribute_target.static_method(),
                             "static_method")

        @context.sub_context
        def class_methods(context):
            @context.example
            def are_not_affected(self):
                self.assertEqual(
                    self.class_attribute_target.regular_class_method(),
                    "regular_class_method",
                )

            @context.example("super(Target, cls) works")
            def p2_super_works(self):
                self.assertEqual(
                    self.class_attribute_target.p2_super_class_method(),
                    "p2_super_class_method",
                )

            @context.example("super() works")
            def p3_super_works(self):
                self.assertEqual(
                    self.class_attribute_target.p3_super_class_method(),
                    "p3_super_class_method",
                )

    @context.sub_context
    def patching_mechanism(context):
        @context.example
        def can_not_mock_constructor_with_existing_instances(self):
            original_target = original_target_class()
            with self.assertRaisesWithMessageInException(
                    RuntimeError,
                    "mock_constructor() can not be used after instances of Target were created: {}"
                    .format([original_target]),
            ):
                self.mock_constructor(
                    self.target_module,
                    self.target_class_name).to_call_original()

        @context.example
        def works_with_composition(self):
            self.mock_constructor(
                self.target_module, self.target_class_name).for_call(
                    "1").with_wrapper(lambda original_callable, *args, **
                                      kwargs: original_callable("one"))
            self.mock_constructor(
                self.target_module, self.target_class_name).for_call(
                    "2").with_wrapper(lambda original_callable, *args, **
                                      kwargs: original_callable("two"))

            target_one = self.get_target_class()("1")
            self.assertEqual(target_one.args, ("one", ))

            target_two = self.get_target_class()("2")
            self.assertEqual(target_two.args, ("two", ))

        @context.sub_context
        def original_class_attribute_access(context):
            @context.before
            def mock_constructor(self):
                self.mock_constructor(
                    self.target_module,
                    self.target_class_name).to_call_original()

            @context.example
            def can_not_create_new_instances(self):
                with self.assertRaisesWithMessageInException(
                        BaseException,
                        "Attribute getting after the class has been used with mock_constructor() is not supported!",
                ):
                    original_target_class()

            @context.example
            def can_access_class_attributes(self):
                self.assertEqual(original_target_class.CLASS_ATTR,
                                 "CLASS_ATTR")

            @context.example
            def can_call_class_methods(self):
                for name in [
                        "regular_class_method",
                        "p2_super_class_method",
                        "p3_super_class_method",
                ]:
                    self.assertEqual(
                        getattr(original_target_class, name)(), name)

            @context.example
            def can_call_static_methods(self):
                self.assertEqual(original_target_class.static_method(),
                                 "static_method")

    @context.sub_context
    def arguments(context):
        @context.example
        def refuses_to_mock_if_instances_exist(self):
            target_instance = self.get_target_class()()  # noqa F841
            with self.assertRaisesWithMessageInException(
                    RuntimeError,
                    "mock_constructor() can not be used after instances of Target were created: ",
            ):
                self.mock_constructor(self.target_module,
                                      self.target_class_name)

        @context.sub_context
        def module(context):
            context.memoize("args", lambda self: ("6", "7"))
            context.memoize("kwargs", lambda self: {"8": "eight", "9": "nine"})

            @context.after
            def assert_working(self):
                mocked_instance = self.get_target_class()(*self.args,
                                                          **self.kwargs)
                self.assertEqual(mocked_instance, "mocked")

            @context.example
            def accepts_string(self):
                self.mock_constructor(
                    self.target_module.__name__,
                    self.target_class_name).for_call(
                        *self.args, **self.kwargs).to_return_value("mocked")

            @context.example
            def accepts_reference(self):
                self.mock_constructor(
                    self.target_module, self.target_class_name).for_call(
                        *self.args, **self.kwargs).to_return_value("mocked")

        @context.sub_context("class")
        def klass(context):
            @context.example
            def rejects_non_string_class_name(self):
                with self.assertRaisesWithMessageInException(
                        ValueError,
                        "Second argument must be a string with the name of the class.",
                ):
                    self.mock_constructor(self.target_module,
                                          original_target_class)

            @context.example
            def rejects_non_class_targets(self):
                with self.assertRaisesWithMessageInException(
                        ValueError, "Target must be a class."):
                    self.mock_constructor(self.target_module,
                                          "function_at_module")

    @context.sub_context
    def class_attributes_at_the_class(context):
        @context.memoize
        def class_attribute_target(self):
            return self.get_target_class()

        context.merge_context("class attributes")

    @context.sub_context("mock_callable() integration")
    def mock_callable_integration(context):
        @context.example
        def it_uses_mock_callable_interface(self):
            self.assertIsInstance(
                self.mock_constructor(self.target_module,
                                      self.target_class_name),
                _MockCallableDSL,
            )

        @context.example
        def registers_call_count_and_args_correctly(self):
            self.mock_constructor(
                self.target_module, self.target_class_name).for_call(
                    "Hello",
                    "World").to_return_value(None).and_assert_called_exactly(2)

            target_class = self.get_target_class()
            t1 = target_class("Hello", "World")
            t2 = target_class("Hello", "World")

            self.assertIsNone(t1)
            self.assertIsNone(t2)

        @context.example
        def mock_constructor_can_not_assert_if_already_received_call(self):
            mock = (self.mock_constructor(self.target_module,
                                          self.target_class_name).for_call(
                                              "Hello",
                                              "World").to_return_value(None))
            target_class = self.get_target_class()
            target_class("Hello", "World")
            with self.assertRaisesRegex(
                    ValueError,
                    "^No extra configuration is allowed after mock_constructor.+self.mock_constructor",
            ):
                mock.and_assert_called_once()

        @context.sub_context
        def behavior(context):
            @context.example(".to_call_original() works")
            def to_call_original_works(self):
                default_args = ("default", )
                specific_args = ("specific", )

                self.mock_constructor(
                    self.target_module,
                    self.target_class_name).to_call_original()
                self.mock_constructor(
                    self.target_module, self.target_class_name).for_call(
                        *specific_args).to_return_value("mocked_target")

                default_target = self.get_target_class()(*default_args)
                self.assertEqual(default_target.args, default_args)

                specific_target = self.get_target_class()(*specific_args)
                self.assertEqual(specific_target, "mocked_target")

            @context.example(".with_implementation() works")
            def with_implementation_works(self):
                args = ("1", "2")
                kwargs = {"one": "2", "two": "2"}

                def implementation(*received_args, **received_kwargs):
                    self.assertEqual(received_args, args)
                    self.assertEqual(received_kwargs, kwargs)
                    return "mock"

                self.mock_constructor(
                    self.target_module,
                    self.target_class_name).with_implementation(implementation)

                self.assertEqual(self.get_target_class()(*args, **kwargs),
                                 "mock")

            @context.sub_context(".with_wrapper()")
            def with_wrapper(context):
                context.memoize("args", lambda self: ("1", "2"))
                context.memoize("wrapped_args", lambda self: ("3", "4"))
                context.memoize("kwargs", lambda self: {
                    "one": "1",
                    "two": "2"
                })
                context.memoize("wrapped_kwargs", lambda self: {
                    "three": "3",
                    "four": "4"
                })

                @context.memoize
                def target(self):
                    return self.get_target_class()(*self.args, **self.kwargs)

                @context.before
                def setup_wrapper(self):
                    def wrapper(original_callable, *args, **kwargs):
                        return original_callable(*self.wrapped_args,
                                                 **self.wrapped_kwargs)

                    self.mock_constructor(
                        self.target_module,
                        self.target_class_name).with_wrapper(wrapper)

                @context.example
                def wrapped_instance_is_instance_of_original_class(self):
                    self.assertIsInstance(self.target, original_target_class)

                @context.example
                def constructor_is_wrapped(self):
                    self.assertSequenceEqual(self.target.args,
                                             self.wrapped_args)
                    self.assertSequenceEqual(self.target.kwargs,
                                             self.wrapped_kwargs)

                @context.example
                def factory_works(self):
                    def factory(original_callable, message):
                        return "got: {}".format(message)

                    self.mock_constructor(self.target_module,
                                          self.target_class_name).for_call(
                                              "factory").with_wrapper(factory)
                    target = self.get_target_class()("factory")
                    self.assertEqual(target, "got: factory")

                @context.sub_context
                def class_attributes_at_the_instance(context):
                    context.memoize("class_attribute_target",
                                    lambda self: self.target)

                    context.merge_context("class attributes")

                @context.sub_context("Target.__init__()")
                def target_init(context):
                    @context.example("super(Target, self)")
                    def p2_super_works(self):
                        target = self.get_target_class()(p2_super=True)
                        self.assertTrue(target.p2_super)

                    @context.example("super() works")
                    def p3_super_works(self):
                        target = self.get_target_class()(p3_super=True)
                        self.assertTrue(target.p3_super)

                    @context.example
                    def can_be_called_again(self):
                        new_args = ("new", "args")
                        new_kwargs = {"new": "kwargs"}
                        self.target.__init__(*new_args, **new_kwargs)
                        self.assertEqual(self.target.args, new_args)
                        self.assertEqual(self.target.kwargs, new_kwargs)

                @context.sub_context
                def instance_methods(context):
                    @context.example
                    def it_works(self):
                        self.assertEqual(
                            self.target.regular_instance_method(),
                            "regular_instance_method",
                        )

                    @context.sub_context
                    def when_it_overloads_parent_method(context):
                        @context.example("super(Target, self) works")
                        def p2_super_works(self):
                            self.assertEqual(
                                self.target.p2_super_instance_method(),
                                "p2_super_instance_method",
                            )

                        @context.example("super() works")
                        def p3_super_works(self):
                            self.assertEqual(
                                self.target.p3_super_instance_method(),
                                "p3_super_instance_method",
                            )

    @context.sub_context
    def StrictMock_integration(context):
        @context.shared_context
        def StrictMock_tests(context):
            @context.before
            def setup(self):
                self.mock_constructor(
                    self.target_module,
                    self.target_class_name).for_call().to_return_value(
                        self.target_mock)
                self.target = self.get_target_class()()

            @context.example
            def patching_works(self):
                self.assertIs(self.target, self.target_mock)

            @context.example("mock_callable() works")
            def mock_callable_works(self):
                self.mock_callable(
                    self.target_mock,
                    "regular_instance_method").for_call().to_return_value(
                        "mocked")
                self.assertEqual(self.target.regular_instance_method(),
                                 "mocked")

            @context.example
            def dynamic_attributes_work(self):
                self.target_mock.dynamic_attr = "mocked_attr"
                self.assertEqual(self.target.dynamic_attr, "mocked_attr")

        @context.function
        def get_target_mock(self):
            return StrictMock(template=self.get_target_class())

        @context.sub_context
        def with_target_mock_memoized_before(context):
            @context.memoize_before
            def target_mock(self):
                return self.get_target_mock()

            context.merge_context("StrictMock tests")

        @context.sub_context
        def with_target_mock_memoized(context):
            @context.memoize
            def target_mock(self):
                return self.get_target_mock()

            context.merge_context("StrictMock tests")

    @context.example
    def private_patching_raises_valueerror(self):
        with self.assertRaises(ValueError):
            self.mock_constructor(self.target_module, _PrivateClass.__name__)

    @context.example
    def private_patching_allow_private(self):
        self.mock_constructor(
            self.target_module, _PrivateClass.__name__,
            allow_private=True).for_call().to_return_value("mocked_private")
        _PrivateClass()

    @context.sub_context
    def type_validation(context):
        context.memoize("value", lambda self: "Target mock")
        context.memoize("type_validation", lambda self: True)

        @context.before
        def before(self):
            self.mock_constructor(
                self.target_module,
                self.target_class_name,
                type_validation=self.type_validation,
            ).to_return_value(self.value)
            self.target = getattr(self.target_module, self.target_class_name)

        @context.example
        def it_passes_with_valid_types(self):
            self.assertEqual(self.target(message="hello"), self.value)

        @context.example
        def it_fails_with_invalid_types(self):
            with self.assertRaises(TypeCheckError):
                self.target(message=1234)

        @context.sub_context("with type_validation=False")
        def with_type_validation_False(context):
            context.memoize("type_validation", lambda self: False)

            @context.example
            def it_passes_with_invalid_types(self):
                self.target(message=1234)
            def with_wrapper(context):
                context.memoize("args", lambda self: ("1", "2"))
                context.memoize("wrapped_args", lambda self: ("3", "4"))
                context.memoize("kwargs", lambda self: {
                    "one": "1",
                    "two": "2"
                })
                context.memoize("wrapped_kwargs", lambda self: {
                    "three": "3",
                    "four": "4"
                })

                @context.memoize
                def target(self):
                    return self.get_target_class()(*self.args, **self.kwargs)

                @context.before
                def setup_wrapper(self):
                    def wrapper(original_callable, *args, **kwargs):
                        return original_callable(*self.wrapped_args,
                                                 **self.wrapped_kwargs)

                    self.mock_constructor(
                        self.target_module,
                        self.target_class_name).with_wrapper(wrapper)

                @context.example
                def wrapped_instance_is_instance_of_original_class(self):
                    self.assertIsInstance(self.target, original_target_class)

                @context.example
                def constructor_is_wrapped(self):
                    self.assertSequenceEqual(self.target.args,
                                             self.wrapped_args)
                    self.assertSequenceEqual(self.target.kwargs,
                                             self.wrapped_kwargs)

                @context.example
                def factory_works(self):
                    def factory(original_callable, message):
                        return "got: {}".format(message)

                    self.mock_constructor(self.target_module,
                                          self.target_class_name).for_call(
                                              "factory").with_wrapper(factory)
                    target = self.get_target_class()("factory")
                    self.assertEqual(target, "got: factory")

                @context.sub_context
                def class_attributes_at_the_instance(context):
                    context.memoize("class_attribute_target",
                                    lambda self: self.target)

                    context.merge_context("class attributes")

                @context.sub_context("Target.__init__()")
                def target_init(context):
                    @context.example("super(Target, self)")
                    def p2_super_works(self):
                        target = self.get_target_class()(p2_super=True)
                        self.assertTrue(target.p2_super)

                    @context.example("super() works")
                    def p3_super_works(self):
                        target = self.get_target_class()(p3_super=True)
                        self.assertTrue(target.p3_super)

                    @context.example
                    def can_be_called_again(self):
                        new_args = ("new", "args")
                        new_kwargs = {"new": "kwargs"}
                        self.target.__init__(*new_args, **new_kwargs)
                        self.assertEqual(self.target.args, new_args)
                        self.assertEqual(self.target.kwargs, new_kwargs)

                @context.sub_context
                def instance_methods(context):
                    @context.example
                    def it_works(self):
                        self.assertEqual(
                            self.target.regular_instance_method(),
                            "regular_instance_method",
                        )

                    @context.sub_context
                    def when_it_overloads_parent_method(context):
                        @context.example("super(Target, self) works")
                        def p2_super_works(self):
                            self.assertEqual(
                                self.target.p2_super_instance_method(),
                                "p2_super_instance_method",
                            )

                        @context.example("super() works")
                        def p3_super_works(self):
                            self.assertEqual(
                                self.target.p3_super_instance_method(),
                                "p3_super_instance_method",
                            )
                def class_attributes_at_the_instance(context):
                    context.memoize("class_attribute_target",
                                    lambda self: self.target)

                    context.merge_context("class attributes")
Пример #5
0
            def composition(context):
                """
                This context takes care of composition of multiple
                call/behavior/assertion combination, to ensure they play along well.
                """

                context.memoize(
                    "other_args",
                    lambda self: ["other_arg" for arg in self.call_args])
                context.memoize(
                    "other_kwargs",
                    lambda self:
                    {k: "other_value"
                     for k, v in self.call_kwargs.items()},
                )

                @context.example
                def newest_mock_has_precedence_over_older_mocks(self):
                    """
                    Mocks are designed to be composable, allowing us to declare
                    multiple behaviors for different calls. Those definitions stack up,
                    and when a call is made to the mock, they are searched from newest
                    to oldest, to find one that is able to be caled.
                    """
                    # First, mock all calls
                    mock_callable(
                        self.target_arg,
                        self.callable_arg).to_return_value("any args")
                    # Then we add some specific call behavior
                    mock_callable(self.target_arg, self.callable_arg).for_call(
                        *self.specific_call_args, **
                        self.specific_call_kwargs).to_return_value("specific")
                    # The first behavior should still be there
                    self.assertEqual(
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs),
                        "any args",
                    )
                    # as well as the specific case
                    self.assertEqual(
                        self.callable_target(*self.specific_call_args,
                                             **self.specific_call_kwargs),
                        "specific",
                    )
                    # but if we add another "catch all" case
                    mock_callable(
                        self.target_arg,
                        self.callable_arg).to_return_value("new any args")
                    # it should take over any previous mock
                    self.assertEqual(
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs),
                        "new any args",
                    )
                    self.assertEqual(
                        self.callable_target(*self.specific_call_args,
                                             **self.specific_call_kwargs),
                        "new any args",
                    )

                @context.sub_context
                def multiple_assertions(context):
                    @context.before
                    def setup_mocks(self):
                        mock_callable(self.target_arg,
                                      self.callable_arg).to_return_value(
                                          "any args").and_assert_called_once()
                        mock_callable(
                            self.target_arg, self.callable_arg).for_call(
                                *self.specific_call_args,
                                **self.specific_call_kwargs).to_return_value(
                                    "specific").and_assert_called_twice()

                    @context.example
                    def that_passes(self):
                        self.callable_target(*self.other_args,
                                             **self.other_kwargs)
                        self.callable_target(*self.specific_call_args,
                                             **self.specific_call_kwargs)
                        self.callable_target(*self.specific_call_args,
                                             **self.specific_call_kwargs)

                    @context.example
                    def that_fails(self):
                        # "Pass" this test when callable accepts no arguments
                        if (self.specific_call_args == self.call_args and
                                self.specific_call_kwargs == self.call_kwargs):
                            raise RuntimeError("FIXME")
                            return
                        self.callable_target(*self.other_args,
                                             **self.other_kwargs)
                        self.callable_target(*self.specific_call_args,
                                             **self.specific_call_kwargs)
                        with self.assertRaises(AssertionError):
                            self.assert_all()
Пример #6
0
 def with_magic_method_defined_on_parent_class(context):
     context.memoize("target", lambda self: Target())
     context.merge_context("magic method tests")
Пример #7
0
    def without_template(context):
        context.memoize("strict_mock", lambda _: StrictMock())

        @context.memoize
        def strict_mock_rgx(self):
            return ("<StrictMock 0x{:02X} ".format(id(self.strict_mock)) +
                    re.escape(self.caller_filename) + ":\d+>")

        context.memoize("value", lambda _: 3241234123)

        context.memoize("test_method_name", lambda _: "some_method")
        context.memoize("mock_function", lambda _: lambda: None)

        context.merge_context("can access attributes")

        @context.example
        def raises_when_an_undefined_attribute_is_accessed(self):
            name = "undefined_attribute"
            with self.assertRaisesWithRegexMessage(
                    AttributeError,
                    f"'{name}' was not set for {self.strict_mock}."):
                getattr(self.strict_mock, name)

        @context.example
        def allows_mocking_any_attribute(self):
            self.strict_mock.any_attribute = self.value
            self.assertEqual(self.strict_mock.any_attribute, self.value)

        @context.example
        def allows_deleting_a_mocked_attribute(self):
            name = "attr_name"
            setattr(self.strict_mock, name, self.value)
            self.assertTrue(hasattr(self.strict_mock, name))
            delattr(self.strict_mock, name)
            with self.assertRaisesWithRegexMessage(
                    AttributeError,
                    f"'{name}' was not set for {self.strict_mock}."):
                getattr(self.strict_mock, name)

        @context.example
        def allows_mocking_any_method(self):
            def value_plus(b):
                return self.value + b

            self.strict_mock.any_method = value_plus
            plus = 2341
            self.assertEqual(self.strict_mock.any_method(plus),
                             self.value + plus)

        @context.example
        def allows_mocking_context_manager_methods(self):
            enter_mock = "something"
            self.strict_mock.__enter__ = lambda: enter_mock
            self.strict_mock.__exit__ = lambda exc_type, exc_value, traceback: None
            with self.strict_mock as target:
                self.assertEqual(target, enter_mock)

        @context.example
        def attribute_type_is_maintained(self):
            callable_attr = CallableObject()
            self.strict_mock.callable_attr = callable_attr
            attr = {1: 2}
            self.strict_mock.attr = attr
            self.assertEqual(type(self.strict_mock.callable_attr),
                             type(callable_attr))
            self.assertEqual(type(self.strict_mock.attr), type(attr))
Пример #8
0
def mock_callable_context(context):

    ##
    ## Common mock_callable setup
    ##

    context.memoize("assertions", lambda _: [])
    context.memoize("call_args", lambda _: ("first", "second"))
    context.memoize("call_kwargs", lambda _: {
        "kwarg1": "first",
        "kwarg2": "second"
    })

    @context.memoize
    def specific_call_args(self):
        return tuple("specific {}".format(arg) for arg in self.call_args)

    @context.memoize
    def specific_call_kwargs(self):
        return {
            k: "specific {}".format(v)
            for k, v in self.call_kwargs.items()
        }

    @context.before
    def register_assertions(self):
        def register_assertion(assertion):
            self.assertions.append(assertion)

        testslide.mock_callable.register_assertion = register_assertion

    @context.after
    def cleanup_patches(self):
        # Unpatch before assertions, to make sure it is done if assertion fails.
        testslide.mock_callable.unpatch_all_callable_mocks()
        for assertion in self.assertions:
            assertion()

    @context.function
    @contextlib.contextmanager
    def assertRaisesWithMessage(self, exception, msg):
        with self.assertRaises(exception) as cm:
            yield
        ex_msg = str(cm.exception)
        self.assertEqual(
            ex_msg,
            msg,
            "Expected exception {}.{} message "
            "to be\n{}\nbut got\n{}.".format(exception.__module__,
                                             exception.__name__, repr(msg),
                                             repr(ex_msg)),
        )

    @context.shared_context
    def examples_for_target(
        context,
        callable_accepts_no_args=False,
        has_original_callable=True,
        can_yield=True,
        validate_signature=True,
    ):
        @context.function
        def assert_all(self):
            try:
                for assertion in self.assertions:
                    assertion()
            finally:
                del self.assertions[:]

        @context.function
        def no_behavior_msg(self):
            if self.call_kwargs:
                kwargs_msg = ("    {\n" + "".join(
                    "      {}={},\n".format(k, self.call_kwargs[k])
                    for k in sorted(self.call_kwargs.keys())) + "    }\n")
            else:
                kwargs_msg = "    {}\n"
            return str("{}, {}:\n".format(repr(self.target_arg),
                                          repr(self.callable_arg)) +
                       "  Received call:\n" +
                       "    {}\n".format(self.call_args) + kwargs_msg +
                       "  But no behavior was defined for it.")

        @context.shared_context
        def mock_call_arguments(context):
            @context.example
            def works_for_matching_signature(self):
                self.callable_target(*self.call_args, **self.call_kwargs),

            if validate_signature and sys.version_info[0] != 2:

                @context.example
                def raises_TypeError_for_mismatching_signature(self):
                    args = ("some", "invalid", "args", "list")
                    kwargs = {"invalid_kwarg": "invalid_value"}
                    with self.assertRaises(TypeError):
                        self.callable_target(*args, **kwargs)

            @context.sub_context(".for_call(*args, **kwargs)")
            def for_call_args_kwargs(context):

                if not callable_accepts_no_args:

                    @context.sub_context
                    def with_matching_signature(context):
                        @context.before
                        def before(self):
                            self.mock_callable_dsl.for_call(
                                *self.specific_call_args,
                                **self.specific_call_kwargs)

                        @context.example
                        def it_accepts_known_arguments(self):
                            self.callable_target(*self.specific_call_args,
                                                 **self.specific_call_kwargs)

                        if validate_signature:

                            @context.example
                            def it_rejects_unknown_arguments(self):
                                with self.assertRaisesWithMessage(
                                        UnexpectedCallArguments,
                                        self.no_behavior_msg() +
                                        "\n  These are the registered calls:\n"
                                        + "    {}\n".format(
                                            self.specific_call_args) +
                                        "    {\n" +
                                        "".join("      {}={},\n".format(
                                            k, self.specific_call_kwargs[k])
                                                for k in sorted(
                                                    self.specific_call_kwargs.
                                                    keys())) + "    }\n",
                                ):
                                    self.callable_target(
                                        *self.call_args, **self.call_kwargs)

                    if validate_signature:

                        @context.sub_context
                        def with_mismatching_signature(context):
                            @context.xexample
                            def it_fails_to_mock(self):
                                with self.assertRaisesWithMessage(
                                        ValueError,
                                        "Can not mock target for arguments that mismatch the "
                                        "original callable signature.",
                                ):
                                    self.mock_callable_dsl.for_call(
                                        "some",
                                        "invalid",
                                        "args",
                                        and_some="invalid",
                                        kwargs="values",
                                    )

        @context.shared_context
        def assertions(context):
            @context.shared_context
            def assert_failure(context):
                @context.after
                def after(self):
                    with self.assertRaises(AssertionError):
                        self.assert_all()

            @context.shared_context
            def not_called(context):
                @context.example
                def not_called(self):
                    pass

            @context.shared_context
            def called_less_times(context):
                @context.example
                def called_less_times(self):
                    for _ in range(self.times - 1):
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs)

            @context.shared_context
            def called_more_times(context):
                @context.example
                def called_more_times(self):
                    for _ in range(self.times + 1):
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs)

            @context.shared_context
            def called_more_times_fail(context):
                @context.example
                def called_more_times(self):
                    for _ in range(self.times):
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs)
                    with self.assertRaisesWithMessage(
                            UnexpectedCallReceived,
                        ("Unexpected call received.\n"
                         "{}, {}:\n"
                         "  expected to receive at most {} calls with any arguments "
                         "  but received an extra call.").format(
                             repr(self.target_arg), repr(self.callable_arg),
                             self.times),
                    ):
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs)

            @context.shared_context
            def called_exactly_times(context):
                @context.example
                def called_exactly_times(self):
                    for _ in range(self.times):
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs)

            @context.sub_context(".and_assert_called_exactly(times)")
            def and_assert_called_exactly(context):
                @context.sub_context
                def with_valid_input(context):
                    @context.before
                    def setup_assertion(self):
                        self.mock_callable_dsl.and_assert_called_exactly(
                            self.times)

                    @context.sub_context
                    def fails_when(context):

                        context.merge_context("assert failure")

                        context.merge_context("not called")
                        context.merge_context("called less times")
                        context.merge_context("called more times fail")

                    @context.sub_context
                    def passes_when(context):

                        context.merge_context("called exactly times")

            @context.sub_context(".and_assert_called_at_least(times)")
            def and_assert_called_at_least(context):
                @context.sub_context
                def with_invalid_input(context):
                    @context.example("fails to mock when times < 1")
                    def fails_to_mock_when_times_1(self):
                        with self.assertRaisesWithMessage(
                                ValueError, "times must be >= 1"):
                            self.mock_callable_dsl.and_assert_called_at_least(
                                0)

                @context.sub_context
                def with_valid_input(context):
                    @context.before
                    def setup_assertion(self):
                        self.mock_callable_dsl.and_assert_called_at_least(
                            self.times)

                    @context.sub_context
                    def fails_when(context):

                        context.merge_context("assert failure")

                        context.merge_context("not called")
                        context.merge_context("called less times")

                    @context.sub_context
                    def passes_when(context):

                        context.merge_context("called exactly times")
                        context.merge_context("called more times")

            @context.sub_context(".and_assert_called_at_most(times)")
            def and_assert_called_at_most(context):
                @context.sub_context
                def with_invalid_input(context):
                    @context.example("fails to mock when times < 1")
                    def fails_to_mock_when_times_1(self):
                        with self.assertRaisesWithMessage(
                                ValueError, "times must be >= 1"):
                            self.mock_callable_dsl.and_assert_called_at_most(0)

                @context.sub_context
                def with_valid_input(context):
                    @context.before
                    def setup_assertion(self):
                        self.mock_callable_dsl.and_assert_called_at_most(
                            self.times)

                    @context.sub_context
                    def fails_when(context):

                        context.merge_context("assert failure")

                        context.merge_context("not called")
                        context.merge_context("called more times fail")

                    @context.sub_context
                    def passes_when(context):

                        context.merge_context("called less times")
                        context.merge_context("called exactly times")

            @context.sub_context(".and_assert_called()")
            def and_assert_called(context):
                @context.before
                def setup_assertion(self):
                    self.mock_callable_dsl.and_assert_called()

                @context.sub_context
                def fails_when(context):

                    context.merge_context("assert failure")

                    context.merge_context("not called")

                @context.sub_context
                def passes_when(context):
                    @context.example
                    def called_once(self):
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs)

                    @context.example
                    def called_several_times(self):
                        for _ in range(self.times + 1):
                            self.callable_target(*self.call_args,
                                                 **self.call_kwargs)

            @context.sub_context(".and_assert_not_called()")
            def and_assert_not_called(context):
                @context.example
                def can_use_with_previously_existing_behavior(self):
                    self.mock_callable_dsl.and_assert_not_called()

        @context.sub_context
        def default_behavior(context):
            @context.example
            def mock_call_fails_with_undefined_behavior(self):
                with self.assertRaisesWithMessage(UndefinedBehaviorForCall,
                                                  self.no_behavior_msg()):
                    self.callable_target(*self.call_args, **self.call_kwargs)

            @context.sub_context(".and_assert_not_called()")
            def and_assert_not_called(context):
                @context.before
                def setup_assertion(self):
                    self.mock_callable_dsl.and_assert_not_called()

                @context.sub_context
                def passes_when(context):
                    @context.example
                    def not_called(self):
                        pass

                @context.sub_context
                def fails_when(context):
                    @context.after
                    def after(self):
                        with self.assertRaises(AssertionError):
                            self.assert_all()

                    @context.example
                    def called(self):
                        with self.assertRaisesWithMessage(
                                UnexpectedCallReceived,
                                "{}, {}: Excepted not to be called!".format(
                                    repr(self.real_target),
                                    repr(self.callable_arg)),
                        ):
                            self.callable_target(*self.call_args,
                                                 **self.call_kwargs)

        @context.sub_context(".to_return(value)")
        def to_return_value(context):

            context.memoize("value", lambda _: "mocked value")
            context.memoize("times", lambda _: 3)

            @context.before
            def setup_mock(self):
                self.mock_callable_dsl.to_return_value(self.value)

            if has_original_callable:
                context.nest_context("mock call arguments")
            context.nest_context("assertions")

            @context.example
            def mock_call_returns_given_value(self):
                self.assertEqual(
                    self.callable_target(*self.call_args, **self.call_kwargs),
                    self.value,
                )
                other_args = ["other_arg" for arg in self.call_args]
                other_kwargs = {k: "other_value" for k in self.call_kwargs}
                self.assertEqual(
                    self.callable_target(*other_args, **other_kwargs),
                    self.value)

        @context.sub_context(".to_return_values(values_list)")
        def to_return_values_values_list(context):

            context.memoize("values_list",
                            lambda _: ["first", "second", "third"])
            context.memoize("times", lambda self: len(self.values_list) - 1)

            @context.before
            def setup_mock(self):
                self.mock_callable_dsl.to_return_values(self.values_list)

            if has_original_callable:
                context.nest_context("mock call arguments")
            context.nest_context("assertions")

            @context.example
            def return_values_from_list_in_order(self):
                for value in self.values_list:
                    self.assertEqual(
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs), value)

            @context.sub_context
            def when_list_is_exhausted(context):
                @context.before
                def before(self):
                    for _ in self.values_list:
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs)

                @context.example
                def it_raises(self):
                    with self.assertRaisesWithMessage(
                            UndefinedBehaviorForCall,
                            "No more values to return!"):
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs)

        if can_yield:

            @context.sub_context(".to_yield_values(values_list)")
            def to_yield_values_values_list(context):

                context.memoize("values_list",
                                lambda _: ["first", "second", "third"])
                context.memoize("times",
                                lambda self: len(self.values_list) - 1)

                @context.before
                def setup_mock(self):
                    self.mock_callable_dsl.to_yield_values(self.values_list)

                if has_original_callable:
                    context.nest_context("mock call arguments")
                context.nest_context("assertions")

                @context.memoize
                def iterable(self):
                    return iter(
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs))

                @context.example
                def yield_values_from_list_in_order(self):
                    for value in self.values_list:
                        self.assertEqual(next(self.iterable), value)

                @context.sub_context
                def when_list_is_empty(context):
                    @context.before
                    def before(self):
                        for _ in self.values_list:
                            next(self.iterable)

                    @context.example
                    def it_raises_StopIteration(self):
                        with self.assertRaises(StopIteration):
                            next(self.iterable)

        @context.sub_context(".to_raise(exception)")
        def to_raise_exception(context):

            context.memoize("exception_class", lambda _: RuntimeError)
            context.memoize("times", lambda _: 3)

            @context.shared_context
            def integration(context):
                @context.before
                def catch_callable_target_exceptions(self):
                    original_callable_target = self.callable_target

                    def _callable_target(*args, **kwargs):
                        with self.assertRaises(self.exception_class):
                            return original_callable_target(*args, **kwargs)

                    self.callable_target = _callable_target

                if has_original_callable:
                    context.nest_context("mock call arguments")
                context.nest_context("assertions")

            @context.sub_context
            def when_given_an_exception_class(context):
                @context.before
                def setup_mock(self):
                    self.mock_callable_dsl.to_raise(self.exception_class)

                @context.example
                def it_raises_an_instance_of_the_class(self):
                    with self.assertRaises(self.exception_class):
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs)

                context.nest_context("integration")

            @context.sub_context
            def when_given_an_exception_instance(context):

                context.memoize("exception_message",
                                lambda _: "test exception")
                context.memoize(
                    "exception",
                    lambda self: self.exception_class(self.exception_message),
                )

                @context.before
                def setup_mock(self):
                    self.mock_callable_dsl.to_raise(self.exception)

                @context.example
                def it_raises_the_exception_instance(self):
                    with self.assertRaises(self.exception_class) as cm:
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs)
                    self.assertEqual(self.exception, cm.exception)

                context.nest_context("integration")

        @context.sub_context(".with_implementation(func)")
        def with_implementation_func(context):

            context.memoize("times", lambda _: 3)
            context.memoize("func_return", lambda _: "mocked response")

            @context.memoize
            def func(self):
                def _func(*args, **kwargs):
                    return self.func_return

                return _func

            @context.before
            def setup_mock(self):
                self.mock_callable_dsl.with_implementation(self.func)

            if has_original_callable:
                context.nest_context("mock call arguments")
            context.nest_context("assertions")

            @context.example
            def it_calls_new_implementation(self):
                self.assertEqual(
                    self.callable_target(*self.call_args, **self.call_kwargs),
                    self.func_return,
                )

        @context.sub_context(".with_wrapper(wrapper_func)")
        def with_wrapper_wrappr_func(context):

            context.memoize("func_return", lambda _: "mocked response")

            @context.memoize
            def wrapper_func(self):
                def _wrapper_func(original_function, *args, **kwargs):
                    self.assertEqual(original_function, self.original_callable)
                    return self.func_return

                return _wrapper_func

            if has_original_callable:

                context.memoize("times", lambda _: 3)

                @context.before
                def setup_mock(self):
                    self.mock_callable_dsl.with_wrapper(self.wrapper_func)

                context.nest_context("mock call arguments")
                context.nest_context("assertions")

                @context.example
                def it_calls_wrapper_function(self):
                    self.assertEqual(
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs),
                        self.func_return,
                    )

            else:

                @context.example
                def it_fails_to_mock(self):
                    with self.assertRaisesWithMessage(
                            ValueError,
                            "Can not wrap original callable that does not exist.",
                    ):
                        self.mock_callable_dsl.with_wrapper(self.wrapper_func)

        @context.sub_context(".to_call_original()")
        def to_call_original(context):

            if has_original_callable:

                context.memoize("times", lambda _: 3)

                @context.before
                def setup_mock(self):
                    self.mock_callable_dsl.to_call_original()

                context.nest_context("mock call arguments")
                context.nest_context("assertions")

                @context.example
                def it_calls_original_implementation(self):
                    self.assertEqual(
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs),
                        self.original_callable(*self.call_args,
                                               **self.call_kwargs),
                    )

            else:

                @context.example
                def it_fails_to_mock(self):
                    with self.assertRaisesWithMessage(
                            ValueError,
                            "Can not call original callable that does not exist.",
                    ):
                        self.mock_callable_dsl.to_call_original()

        if not callable_accepts_no_args:

            @context.sub_context
            def composition(context):
                """
                This context takes care of composition of multiple
                call/behavior/assertion combination, to ensure they play along well.
                """

                context.memoize(
                    "other_args",
                    lambda self: ["other_arg" for arg in self.call_args])
                context.memoize(
                    "other_kwargs",
                    lambda self:
                    {k: "other_value"
                     for k, v in self.call_kwargs.items()},
                )

                @context.example
                def newest_mock_has_precedence_over_older_mocks(self):
                    """
                    Mocks are designed to be composable, allowing us to declare
                    multiple behaviors for different calls. Those definitions stack up,
                    and when a call is made to the mock, they are searched from newest
                    to oldest, to find one that is able to be caled.
                    """
                    # First, mock all calls
                    mock_callable(
                        self.target_arg,
                        self.callable_arg).to_return_value("any args")
                    # Then we add some specific call behavior
                    mock_callable(self.target_arg, self.callable_arg).for_call(
                        *self.specific_call_args, **
                        self.specific_call_kwargs).to_return_value("specific")
                    # The first behavior should still be there
                    self.assertEqual(
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs),
                        "any args",
                    )
                    # as well as the specific case
                    self.assertEqual(
                        self.callable_target(*self.specific_call_args,
                                             **self.specific_call_kwargs),
                        "specific",
                    )
                    # but if we add another "catch all" case
                    mock_callable(
                        self.target_arg,
                        self.callable_arg).to_return_value("new any args")
                    # it should take over any previous mock
                    self.assertEqual(
                        self.callable_target(*self.call_args,
                                             **self.call_kwargs),
                        "new any args",
                    )
                    self.assertEqual(
                        self.callable_target(*self.specific_call_args,
                                             **self.specific_call_kwargs),
                        "new any args",
                    )

                @context.sub_context
                def multiple_assertions(context):
                    @context.before
                    def setup_mocks(self):
                        mock_callable(self.target_arg,
                                      self.callable_arg).to_return_value(
                                          "any args").and_assert_called_once()
                        mock_callable(
                            self.target_arg, self.callable_arg).for_call(
                                *self.specific_call_args,
                                **self.specific_call_kwargs).to_return_value(
                                    "specific").and_assert_called_twice()

                    @context.example
                    def that_passes(self):
                        self.callable_target(*self.other_args,
                                             **self.other_kwargs)
                        self.callable_target(*self.specific_call_args,
                                             **self.specific_call_kwargs)
                        self.callable_target(*self.specific_call_args,
                                             **self.specific_call_kwargs)

                    @context.example
                    def that_fails(self):
                        # "Pass" this test when callable accepts no arguments
                        if (self.specific_call_args == self.call_args and
                                self.specific_call_kwargs == self.call_kwargs):
                            raise RuntimeError("FIXME")
                            return
                        self.callable_target(*self.other_args,
                                             **self.other_kwargs)
                        self.callable_target(*self.specific_call_args,
                                             **self.specific_call_kwargs)
                        with self.assertRaises(AssertionError):
                            self.assert_all()

    ##
    ## Target types
    ##

    @context.sub_context
    def When_target_is_function_of_a_module(context):
        @context.before
        def before(self):
            self.original_callable = testslide._test_function
            self.real_target = testslide
            self.target_arg = "testslide"
            self.callable_arg = "_test_function"
            self.mock_callable_dsl = mock_callable(self.target_arg,
                                                   self.callable_arg)
            self.callable_target = testslide._test_function

        context.merge_context("examples for target")

        @context.example
        def works_with_alternative_module_names(self):
            target = "os.path"
            target_module = os.path
            alternative_target = "testslide.cli.os.path"
            import testslide.cli

            alternative_target_module = testslide.cli.os.path
            original_function = os.path.exists

            self.mock_callable(
                target, "exists").for_call("found").to_return_value(True)
            self.mock_callable(
                alternative_target,
                "exists").for_call("not_found").to_return_value(False)
            self.assertTrue(target_module.exists("found"))
            self.assertTrue(alternative_target_module.exists("found"))
            self.assertFalse(target_module.exists("not_found"))
            self.assertFalse(alternative_target_module.exists("not_found"))
            testslide.mock_callable.unpatch_all_callable_mocks()
            self.assertEqual(os.path.exists, original_function,
                             "Unpatch did not work")

    @context.sub_context
    def When_target_is_a_builtin(context):
        context.memoize("call_args", lambda _: (0, ))
        context.memoize("call_kwargs", lambda _: {})
        context.memoize("specific_call_args", lambda _: (0.000000001, ))
        context.memoize("specific_call_kwargs", lambda _: {})

        @context.before
        def before(self):
            self.original_callable = time.sleep
            self.real_target = time
            self.target_arg = "time"
            self.callable_arg = "sleep"
            self.mock_callable_dsl = mock_callable(self.target_arg,
                                                   self.callable_arg)
            self.callable_target = time.sleep

        context.merge_context("examples for target", validate_signature=False)

    @context.sub_context
    def When_target_is_instance_method_at_a_class(context):
        @context.example
        def it_is_not_allowed(self):
            with self.assertRaises(ValueError):
                mock_callable(Target, "instance_method")

    @context.sub_context
    def When_target_is_class_method_at_a_class(context):
        @context.before
        def before(self):
            self.original_callable = Target.class_method
            self.real_target = Target
            self.target_arg = Target
            self.callable_arg = "class_method"
            self.mock_callable_dsl = mock_callable(self.target_arg,
                                                   self.callable_arg)
            self.callable_target = Target.class_method

        context.merge_context("examples for target")

    @context.sub_context
    def When_target_is_static_method_at_a_class(context):
        @context.before
        def before(self):
            self.original_callable = Target.static_method
            self.real_target = Target
            self.target_arg = Target
            self.callable_arg = "static_method"
            self.mock_callable_dsl = mock_callable(self.target_arg,
                                                   self.callable_arg)
            self.callable_target = Target.static_method

        context.merge_context("examples for target")

    @context.shared_context
    def other_instances_are_not_mocked(context):
        @context.example
        def other_instances_are_not_mocked(self):
            mock_callable(self.target_arg,
                          self.callable_arg).to_return_value("mocked value")
            self.assertEqual(
                self.callable_target(*self.call_args, **self.call_kwargs),
                "mocked value",
            )
            self.assertEqual(
                getattr(Target(), self.callable_arg)(*self.call_args,
                                                     **self.call_kwargs),
                "original response",
            )

    @context.sub_context
    def When_target_is_instance_method_at_an_instance(context):

        context.memoize("callable_arg", lambda _: "instance_method")

        @context.before
        def before(self):
            target = Target()
            self.original_callable = target.instance_method
            self.real_target = target
            self.target_arg = target
            self.mock_callable_dsl = mock_callable(self.target_arg,
                                                   self.callable_arg)
            self.callable_target = target.instance_method

        context.merge_context("examples for target")
        context.merge_context("other instances are not mocked")

    @context.sub_context
    def When_target_is_magic_instance_method_at_an_instance(context):

        context.memoize("call_args", lambda _: ())
        context.memoize("call_kwargs", lambda _: {})

        @context.shared_context
        def magic_method_tests(context):
            @context.before
            def before(self):
                self.original_callable = self.target.__str__
                self.real_target = self.target
                self.target_arg = self.target
                self.callable_arg = "__str__"
                self.mock_callable_dsl = mock_callable(self.target_arg,
                                                       self.callable_arg)
                self.callable_target = lambda: str(self.target)

            context.merge_context("examples for target",
                                  callable_accepts_no_args=True,
                                  can_yield=False)

            @context.example
            def other_instances_are_not_mocked(self):
                mock_callable(
                    self.target_arg,
                    self.callable_arg).to_return_value("mocked value")
                self.assertEqual(self.callable_target(), "mocked value")
                self.assertEqual(str(Target()), "original response")

        @context.sub_context
        def with_magic_method_defined_on_class(context):
            context.memoize("target", lambda self: ParentTarget())
            context.merge_context("magic method tests")

        @context.sub_context
        def with_magic_method_defined_on_parent_class(context):
            context.memoize("target", lambda self: Target())
            context.merge_context("magic method tests")

    @context.shared_context
    def class_is_not_mocked(context):
        @context.example
        def class_is_not_mocked(self):
            mock_callable(self.target_arg,
                          self.callable_arg).to_return_value("mocked value")
            self.assertEqual(
                self.callable_target(*self.call_args, **self.call_kwargs),
                "mocked value",
            )
            self.assertEqual(
                getattr(Target, self.callable_arg)(*self.call_args,
                                                   **self.call_kwargs),
                "original response",
            )

    @context.sub_context
    def When_target_is_class_method_at_an_instance(context):
        @context.before
        def before(self):
            target = Target()
            self.original_callable = target.class_method
            self.real_target = target
            self.target_arg = target
            self.callable_arg = "class_method"
            self.mock_callable_dsl = mock_callable(self.target_arg,
                                                   self.callable_arg)
            self.callable_target = target.class_method

        context.merge_context("examples for target")
        context.merge_context("other instances are not mocked")
        context.merge_context("class is not mocked")

    @context.sub_context
    def When_target_is_static_method_at_an_instance(context):
        @context.before
        def before(self):
            target = Target()
            self.original_callable = target.static_method
            self.real_target = target
            self.target_arg = target
            self.callable_arg = "static_method"
            self.mock_callable_dsl = mock_callable(self.target_arg,
                                                   self.callable_arg)
            self.callable_target = target.static_method

        context.merge_context("examples for target")
        context.merge_context("other instances are not mocked")
        context.merge_context("class is not mocked")

    @context.sub_context
    def When_target_is_a_StrictMock_instance(context):
        @context.shared_context
        def other_instances_are_not_mocked(context, runtime_attrs=[]):
            @context.example
            def other_instances_are_not_mocked(self):
                mock_callable(
                    self.target_arg,
                    self.callable_arg).to_return_value("mocked value")
                self.assertEqual(
                    self.callable_target(*self.call_args, **self.call_kwargs),
                    "mocked value",
                )
                other_strict_mock = StrictMock(template=Target,
                                               runtime_attrs=runtime_attrs)
                mock_callable(
                    other_strict_mock,
                    self.callable_arg).to_return_value("other mocked value")
                self.assertEqual(
                    getattr(other_strict_mock,
                            self.callable_arg)(*self.call_args,
                                               **self.call_kwargs),
                    "other mocked value",
                )

        @context.sub_context
        def And_attribute_is_a_instance_method(context):

            context.memoize("callable_arg", lambda _: "instance_method")

            @context.before
            def before(self):
                target = StrictMock(template=Target)
                self.original_callable = None
                self.real_target = target
                self.target_arg = target
                self.mock_callable_dsl = mock_callable(self.target_arg,
                                                       self.callable_arg)
                self.callable_target = target.instance_method

            context.merge_context("examples for target",
                                  has_original_callable=False)

            context.merge_context("other instances are not mocked")

        @context.sub_context
        def And_attribute_is_a_magic_instance_method(context):

            context.memoize("call_args", lambda _: ())
            context.memoize("call_kwargs", lambda _: {})

            @context.before
            def before(self):
                target = StrictMock(template=Target)
                self.original_callable = None
                self.real_target = target
                self.target_arg = target
                self.callable_arg = "__str__"
                self.mock_callable_dsl = mock_callable(self.target_arg,
                                                       self.callable_arg)
                self.callable_target = lambda: str(target)

            context.merge_context(
                "examples for target",
                callable_accepts_no_args=True,
                has_original_callable=False,
                can_yield=False,
            )

            context.merge_context("other instances are not mocked")

        @context.sub_context
        def And_attribute_is_a_dynamic_instance_method(context):

            context.memoize("callable_arg",
                            lambda _: "dynamic_instance_method")

            @context.before
            def before(self):
                target = StrictMock(template=Target,
                                    runtime_attrs=["dynamic_instance_method"])
                self.original_callable = None
                self.real_target = target
                self.target_arg = target
                self.mock_callable_dsl = mock_callable(self.target_arg,
                                                       self.callable_arg)
                self.callable_target = target.dynamic_instance_method

            context.merge_context("examples for target",
                                  has_original_callable=False)

            context.merge_context(
                "other instances are not mocked",
                runtime_attrs=["dynamic_instance_method"],
            )

        @context.sub_context
        def And_attribute_is_a_class_method(context):
            @context.before
            def before(self):
                target = StrictMock(template=Target)
                self.original_callable = None
                self.real_target = target
                self.target_arg = target
                self.callable_arg = "class_method"
                self.mock_callable_dsl = mock_callable(self.target_arg,
                                                       self.callable_arg)
                self.callable_target = target.class_method

            context.merge_context("examples for target",
                                  has_original_callable=False)
            context.merge_context("other instances are not mocked")
            context.merge_context("class is not mocked")

        @context.sub_context
        def And_attribute_is_a_static_method(context):
            @context.before
            def before(self):
                target = StrictMock(template=Target)
                self.original_callable = None
                self.real_target = target
                self.target_arg = target
                self.callable_arg = "static_method"
                self.mock_callable_dsl = mock_callable(self.target_arg,
                                                       self.callable_arg)
                self.callable_target = target.static_method

            context.merge_context("examples for target",
                                  has_original_callable=False)
            context.merge_context("other instances are not mocked")
            context.merge_context("class is not mocked")
Пример #9
0
def patch_attribute_tests(context):
    ##
    ## Attributes
    ##

    context.memoize("new_value", lambda self: "new_value")

    ##
    ## Functions
    ##

    ##
    ## Hooks
    ##

    ##
    ## Shared Contexts
    ##

    @context.shared_context
    def patching_works(context):
        @context.example
        def patching_works(self):
            def sm_hasattr(obj, name):
                try:
                    return hasattr(obj, name)
                except UndefinedAttribute:
                    return False

            if sm_hasattr(self.real_target, self.attribute):
                original_value = getattr(self.real_target, self.attribute)
            else:
                original_value = None
            self.assertNotEqual(original_value, self.new_value)
            self.patch_attribute(self.target, self.attribute, self.new_value)
            self.assertEqual(getattr(self.real_target, self.attribute), self.new_value)
            unpatch_all_mocked_attributes()
            if original_value:
                self.assertEqual(
                    getattr(self.real_target, self.attribute), original_value
                )
            else:
                self.assertFalse(sm_hasattr(self.real_target, self.attribute))

    @context.shared_context
    def common(context, fails_if_class_attribute):
        context.merge_context("patching works")

        @context.example
        def it_fails_if_attribute_is_callable(self):
            with self.assertRaisesRegex(ValueError, "^Attribute can not be callable*"):
                self.patch_attribute(
                    self.target, self.callable_attribute, self.new_value
                )

        if fails_if_class_attribute:

            @context.example
            def it_fails_if_attribute_is_a_class(self):
                with self.assertRaisesRegex(
                    ValueError, "^Attribute can not be a class*"
                ):
                    self.patch_attribute(
                        self.target, self.class_attribute, self.new_value
                    )

        else:

            @context.sub_context
            def with_class_attributes(context):
                context.merge_context("patching works")

        @context.xexample
        def it_fails_if_new_value_is_of_incompatible_type(self):
            pass

    ##
    ## Contexts
    ##

    @context.sub_context
    def when_target_is_a_module(context):
        context.memoize("callable_attribute", lambda self: "test_function")
        context.memoize("class_attribute", lambda self: "SomeClass")
        context.memoize("attribute", lambda self: "attribute")

        @context.sub_context
        def given_as_a_reference(context):
            context.memoize("target", lambda self: sample_module)
            context.memoize("real_target", lambda self: self.target)
            context.merge_context("common", fails_if_class_attribute=True)

        @context.sub_context
        def given_as_a_string(context):
            context.memoize("target", lambda self: "tests.sample_module")
            context.memoize("real_target", lambda self: sample_module)
            context.merge_context("common", fails_if_class_attribute=True)

    @context.sub_context
    def when_target_is_a_class(context):
        context.memoize("target", lambda self: sample_module.SomeClass)
        context.memoize("real_target", lambda self: self.target)
        context.memoize("callable_attribute", lambda self: "method")
        context.memoize("class_attribute", lambda self: "other_class_attribute")
        context.memoize("attribute", lambda self: "attribute")
        context.merge_context("common", fails_if_class_attribute=False)

        @context.sub_context
        def when_target_is_an_instance(context):
            context.memoize("target", lambda self: sample_module.SomeClass())
            context.memoize("real_target", lambda self: self.target)
            context.merge_context("common", fails_if_class_attribute=False)

            @context.sub_context
            def and_attribute_is_a_property(context):
                context.merge_context("common", fails_if_class_attribute=False)

    @context.sub_context
    def when_target_is_a_StrictMock(context):
        context.memoize("real_target", lambda self: self.target)
        context.memoize("callable_attribute", lambda self: "method")
        context.memoize("class_attribute", lambda self: "other_class_attribute")
        context.memoize("attribute", lambda self: "attribute")

        @context.sub_context
        def with_a_template(context):
            context.memoize(
                "target", lambda self: StrictMock(template=sample_module.SomeClass)
            )

            context.merge_context("common", fails_if_class_attribute=False)

        @context.sub_context
        def without_a_template(context):
            context.memoize("target", lambda self: StrictMock())
            context.merge_context("patching works")

    @context.example
    def patch_attribute_raises_valueerror_for_private(self):
        with self.assertRaises(ValueError):
            self.patch_attribute(
                sample_module.SomeClass, "_private_attr", "notsoprivate"
            )

    @context.example
    def patch_attribute_passes_for_private_with_allow_private(self):
        self.patch_attribute(
            sample_module.SomeClass, "_private_attr", "notsoprivate", allow_private=True
        )
Пример #10
0
 def without_a_template(context):
     context.memoize("target", lambda self: StrictMock())
     context.merge_context("patching works")
Пример #11
0
        def with_a_template(context):
            context.memoize(
                "target", lambda self: StrictMock(template=sample_module.SomeClass)
            )

            context.merge_context("common", fails_if_class_attribute=False)
Пример #12
0
 def given_as_a_string(context):
     context.memoize("target", lambda self: "tests.sample_module")
     context.memoize("real_target", lambda self: sample_module)
     context.merge_context("common", fails_if_class_attribute=True)
Пример #13
0
 def given_as_a_reference(context):
     context.memoize("target", lambda self: sample_module)
     context.memoize("real_target", lambda self: self.target)
     context.merge_context("common", fails_if_class_attribute=True)
 def and_attribute_is_a_property(context):
     context.memoize("attribute", lambda self: "property_attribute")
     context.merge_context("common", fails_if_class_attribute=False)
def patch_attribute_tests(context):
    ##
    ## Attributes
    ##

    context.memoize("new_value", lambda self: "new_value")

    ##
    ## Functions
    ##

    ##
    ## Hooks
    ##

    ##
    ## Shared Contexts
    ##

    @context.shared_context
    def patching_works(context):
        @context.function
        def strict_mock_hasattr(self, obj, name):
            try:
                return hasattr(obj, name)
            except UndefinedAttribute:
                return False

        @context.before
        def before(self):
            if self.strict_mock_hasattr(self.real_target, self.attribute):
                self.original_value = getattr(self.real_target, self.attribute)
            else:
                self.original_value = None
            self.assertNotEqual(
                self.original_value,
                self.new_value,
                "Previous test tainted this result!",
            )

        @context.after
        def after(self):
            self.assertEqual(
                getattr(self.real_target, self.attribute),
                self.new_value,
                "Patching did not work",
            )

            unpatch_all_mocked_attributes()
            if self.original_value:
                self.assertEqual(
                    getattr(self.real_target, self.attribute),
                    self.original_value,
                    "Unpatching did not work.",
                )
            else:
                self.assertFalse(
                    self.strict_mock_hasattr(self.real_target, self.attribute),
                    "Unpatching did not work",
                )

        @context.example
        def patching_works(self):
            self.patch_attribute(self.target, self.attribute, self.new_value)

        @context.example
        def double_patching_works(self):
            self.patch_attribute(self.target, self.attribute, "whatever")
            self.patch_attribute(self.target, self.attribute, self.new_value)

    @context.shared_context
    def common(context, fails_if_class_attribute):
        context.nest_context("patching works")

        @context.example
        def it_fails_if_attribute_is_callable(self):
            with self.assertRaisesRegex(ValueError,
                                        "^Attribute can not be callable*"):
                self.patch_attribute(self.target, self.callable_attribute,
                                     self.new_value)

        if fails_if_class_attribute:

            @context.example
            def it_fails_if_attribute_is_a_class(self):
                with self.assertRaisesRegex(ValueError,
                                            "^Attribute can not be a class*"):
                    self.patch_attribute(self.target, self.class_attribute,
                                         self.new_value)

        else:

            @context.sub_context
            def with_class_attributes(context):
                context.merge_context("patching works")

        @context.sub_context
        def type_validation(context):
            @context.example
            def it_fails_if_new_value_is_of_incompatible_type(self):
                with self.assertRaises(TypeCheckError):
                    self.patch_attribute(self.target, "typedattr", 123)

            @context.example
            def it_passes_if_new_value_is_of_incompatible_type_with_type_validation_false(
                self, ):
                self.patch_attribute(self.target,
                                     "typedattr",
                                     123,
                                     type_validation=False)

            @context.example
            def it_passes_if_new_value_is_of_matching_type(self, ):
                self.patch_attribute(self.target, "typedattr", "mocked")

    ##
    ## Contexts
    ##

    @context.sub_context
    def when_target_is_a_module(context):
        context.memoize("callable_attribute", lambda self: "test_function")
        context.memoize("class_attribute", lambda self: "SomeClass")
        context.memoize("attribute", lambda self: "attribute")

        @context.sub_context
        def given_as_a_reference(context):
            context.memoize("target", lambda self: sample_module)
            context.memoize("real_target", lambda self: self.target)
            context.merge_context("common", fails_if_class_attribute=True)

        @context.sub_context
        def given_as_a_string(context):
            context.memoize("target", lambda self: "tests.sample_module")
            context.memoize("real_target", lambda self: sample_module)
            context.merge_context("common", fails_if_class_attribute=True)

    @context.sub_context
    def when_target_is_a_class(context):
        context.memoize("target", lambda self: sample_module.SomeClass)
        context.memoize("real_target", lambda self: self.target)
        context.memoize("callable_attribute", lambda self: "method")
        context.memoize("class_attribute",
                        lambda self: "other_class_attribute")
        context.memoize("attribute", lambda self: "attribute")
        context.merge_context("common", fails_if_class_attribute=False)

        @context.sub_context
        def when_target_is_an_instance(context):
            context.memoize("target", lambda self: sample_module.SomeClass())
            context.memoize("real_target", lambda self: self.target)
            context.merge_context("common", fails_if_class_attribute=False)

            @context.sub_context
            def and_attribute_is_a_property(context):
                context.memoize("attribute", lambda self: "property_attribute")
                context.merge_context("common", fails_if_class_attribute=False)

    @context.sub_context
    def when_target_is_a_StrictMock(context):
        context.memoize("real_target", lambda self: self.target)
        context.memoize("callable_attribute", lambda self: "method")
        context.memoize("class_attribute",
                        lambda self: "other_class_attribute")
        context.memoize("attribute", lambda self: "attribute")

        @context.sub_context
        def with_a_template(context):
            context.memoize(
                "target",
                lambda self: StrictMock(template=sample_module.SomeClass))

            context.merge_context("common", fails_if_class_attribute=False)

        @context.sub_context
        def without_a_template(context):
            context.memoize("target", lambda self: StrictMock())
            context.merge_context("patching works")

    @context.example
    def patch_attribute_raises_valueerror_for_private(self):
        with self.assertRaises(ValueError):
            self.patch_attribute(sample_module.SomeClass, "_private_attr",
                                 "notsoprivate")

    @context.example
    def patch_attribute_passes_for_private_with_allow_private(self):
        self.patch_attribute(sample_module.SomeClass,
                             "_private_attr",
                             "notsoprivate",
                             allow_private=True)