Most advice on Python mocking is couched in short snippets outside of the unit test framework. This one works find, I'm trying to follow this advice, but it's not successful as soon as I embed it in a proper unit test. For example, this code which produces the output in the comment at the end:
# foo.py
def some_fn():
return 'some_fn'
class Foo( object ):
def method_1( self ):
return some_fn()
# bar.py (depends on foo.py)
import foo
class Bar( object ):
def method_2( self ):
tmp = foo.Foo()
return tmp.method_1()
# test.py (tests bar.py)
import unittest
import bar
from mock import patch
class Test( unittest.TestCase ):
def setUp( self ):
pass
def tearDown( self ):
pass
@patch( 'foo.some_fn' )
def test_bar( self, mock_some_fn ):
mock_some_fn.return_value = 'test-val-1'
tmp = bar.Bar()
print tmp.method_2()
self.assertEqual( tmp.method_2(), 'test-val-1' ) # line 32
mock_some_fn.return_value = 'test-val-2'
self.assertEqual( tmp.method_2(), 'test-val-2' )
if __name__ == "__main__":
unittest.main()
Which I run in PyDev and see:
Finding files... done.
Importing test modules ... done.
some_fn
======================================================================
FAIL: test_bar (test.foo.all.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/mock.py", line 1201, in patched
return func(*args, **keywargs)
File "/home/russ/dev/workspace/python-mocking/test/foo/all.py", line 32, in test_bar
self.assertEqual( tmp.method_2(), 'test-val-1' )
AssertionError: 'some_fn' != 'test-val-1'
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (failures=1)
Remove the unit test framework and this code runs fine (here, just the test.py part of the whole file):
...
# test.py (tests bar.py)
import bar
from mock import patch
@patch( 'foo.some_fn' )
def test_bar( mock_some_fn ):
mock_some_fn.return_value = 'test-val-1'
tmp = bar.Bar()
print tmp.method_2()
assert tmp.method_2() == 'test-val-1'
mock_some_fn.return_value = 'test-val-2'
assert tmp.method_2() == 'test-val-2'
which successfully produces, when run:
~/dev/workspace/python-mocking/test/foo $ python
Python 2.7.5 (default, Nov 3 2014, 14:26:24)
...
>>> import all0
>>> all0.test_bar()
test-val-1
What additional must I do to make this behave in the unit test framework?
The answer for me, a Python and PyDev neophyte, is that this is a PyDev problem. PyDev appears very touchy about how a project's unit testing is set up. I succeeded in making this code work by knitting together a new project set up exactly as this, including separate files.
python-mocking
+-- mocking_example
+-- test
| +-- __init__.py
| `-- test.py
+-- __init__.py
+-- bar.py
`-- foo.py
It might be worth noting that the structure above makes it so that, in test.py, bar must be imported thus:
import mocking_example.bar
and consumed that way, i.e.:
tmp = mocking_example.bar.Bar()