Reputation: 948
I'm using Python 2.6.6
What I'm trying to do is replace the creation of an object with a Mock, to make sure that the correct calls are made. Should be straightforward.
My Module:
import dir.SubModule
class Cls( object ):
def Start( self ):
self.__obj = dir.SubModule.SubCls()
self.__obj.foo()
My Test:
import MyModule
import unittest
from mock import Mock, MagicMock, patch
class MyTest( unittest.TestCase ):
def setUp( self ):
self.uut = MyModule.Cls()
def test_one( self ):
with patch( 'dir.SubModule.SubCls', spec=True ) as mockObj:
print "mock calls before"
print mockObj.mock_calls
self.uut.Start()
print "called: " + str( mockObj.called )
print "foo called: " + str( mockObj.foo.called )
print "call_count: " + str( mockObj.call_count )
print "call_args: " + str( mockObj.call_args )
print "args_list: " + str( mockObj.call_args_list )
print "mock calls:\n" + str( mockObj.mock_calls )
print "method calls:\n " + str( mockObj.method_calls )
The output is:
mock calls before:
[]
called: True
foo called: False
call_count: 1
call_args: call()
args_list: [call()]
mock calls:
[call(), call().foo()]
method calls:
[]
Yet the test fails:
AssertionError: Expected call: foo()
Not called
I don't get how the mock can report that the calls were made, but I can't assert that they were called. What am I missing?
EDIT: After adding in reporting of all the metrics, it seems there is something fundamental that I'm misunderstanding about python mocks. If foo() is in the calls list, then why is the call count only 1, and why does foo.called report 'False'?
Upvotes: 1
Views: 9838
Reputation: 2484
Mock assert syntax has many quirks. To handle it I wrote a helper library to generate the asserts for me.
Here is how you would use it for your test method:
import MyModule
import unittest
from mock import patch
class MyTest( unittest.TestCase ):
def setUp( self ):
self.uut = MyModule.Cls()
def test_one( self ):
with patch( 'dir.SubModule.SubCls', spec=True ) as mockObj:
self.uut.Start()
# calls to generate_asserts, put this after the 'act'
import mock_autogen.generator
print(mock_autogen.generator.generate_asserts(mockObj))
The output you get is:
assert 1 == mockObj.call_count
mockObj.assert_called_once_with()
mockObj.return_value.foo.assert_called_once_with()
Which correlates to the __init__
call, followed by the call to foo
of the newly created object.
So no more need to figure out the exact syntax by yourself, just apply the tool :)
Upvotes: 0
Reputation: 948
Here is the link: link
My simple fix:
with patch( 'class' ) as mockCreator:
mockObj = mockCreator.return_value
Then I can use 'mockObj' willy-nilly.
I ran across the linked solution last week when I was first learning about mocks - a bit too soon for the information to quite sink in.
Upvotes: 0
Reputation: 282026
mockObj.foo
is never called in this test. self.uut.Start()
calls mockObj
, creating a new mock, and then calls that mock's foo
method. If you want to assert that this call happened, you will need to access the correct object:
mockObj.return_value.foo.assert_called_with()
Upvotes: 9