mattys_mocks

Yet another mocking library


License
Other
Install
pip install mattys_mocks==0.1.2

Documentation

#MattysMocks

##Suggested Use

It is suggested that the main way to use this library is though the patch decorators. Using a decorator removes the task of patching from the context of the test. I believe this is desirable because it removes errors resulting from managing mocked objects and greatly increases the readability your tests.

##MockObject

MockObject()

methods

  • attribute_calls - returns a list of all gets and sets of attributes all
  • all_calls - returns a list of all method and attribute calls
  • Creates mocks for methods that have not yet been defined, but will throw a warning for methods not defined
  • ask a method directly about calls made to it

###MockMethod method

  • returns
  • was_called
  • calls

##Patch ###PatchObject methods

  • instances
  • first_instance
  • class_method_calls
  • all_calls - all class method, instance method, and attribute calls
  • all_method_calls - a list of all instance method calls
  • all_attribute_calls

The PatchObject class creates a class like object. While MockObject creates a replacement for object for instance level interactions. PatchObject helps keep track of Class level interactions like class_methods and instances.

def test_patch_object(self):
    ClassLikeObject = PatchObject()
    
    ClassLikeObject.newclassmehtod()
    
    new_instance_mock = ClassLikeObject()
    new_instance_mock.somemethod()
    
    self.assertEqual(len(ClassLikeObject.class_method_calls), 1)
    self.assertEqual(ClassLikeObject.insances[0], new_instance)
    self.assertTrue(ClassLikeObject.instances[0].somemethod.was_called)

###patch.object decorator

Simple example

@patch.object('mock_these.parent_class.DumbClass')
def test_simple_patch(self, dumb_patch):
    pc = ParentClass()
    pc.method_that_uses_dumb_class()
    
    self.assertEqual(len(dumb_patch.first_instance.calls), 1)

Add a method or override what it returns

@patch.object('mock_these.parent_class.DumbClass', methods=['new_method'])
def test_new_method(self, dumb_patch):
    dumb_instance = dumb_patch()
    dumb_instance.new_method # doesn't throw a warning
   
    self.assertTrue(dumb_instance.new_method.was_called)
    
@patch.object('mock_these.parent_class.DumbClass', methods={'somemethod':"new return value"})
def test_override_return(self, dumb_patch):
    pc = ParentClass()
    self.assertEqual(pc.method_that_return_value_for_dumb_some_method(), "new return value")

Adding attributes or set initial return values is simular to methods

@patch.object('mock_these.parent_class.DumbClass', attributes=['new_attribute'])
def test_new_attribute(self, dumb_patch):
    dumb_instance = dumb_patch()
    dumb_instance.new_attribute = "test thing" 
   
    self.assertEqual(len(dumb_patch.attribute_calls), 1)
    
@patch.object('mock_these.parent_class.DumbClass', attributes={'someattribute':"initial value"})
def test_attribute_with_initial_value(self, dumb_patch):
    dumb_instance = dumb_patch() 
    self.assertEqual(dumb_instance.someattribute, "initial value")
    self.assertEqual(len(dumb_patch.attribute_calls), 1)

The mock object will throw warnings for methods that aren't found on patched object.

###patch.function

...
import tests.mock_these.bunch_of_functions as bof
...

class TestPatchFunction(TestCase):
    @patch.function("tests.mock_these.bunch_of_functions.a_function", returns="new_value")
    def test_patch_should_replace_function_with_return_value(self, function_mock):
        self.assertEqual(bof.a_function(), "new_value")

##templating

manually create a mock_object from template using the object.mock.

templated_mock = object.mock(DumbClass)
templated_mock_with_extra_stuff = object.mock(DumbClass, methods=[], attributes=[])

##Future effors

  • allow for dynamic return values for methods