Reputation: 1920
Not wanting to test manually my code, I'm trying to write a test which mocks/patches one of my dependencies (PyInquirer is a pretty neat package which handles the CLI for me - question dicts in, answer dicts out).
However, being very new to Python, I'm having difficulties with mocking that dependency. Here's the code I'm testing:
from PyInquirer import prompt
class Foo:
def bar(self):
# this line is asking the user for inpit, and that's what I want to mock.
a = prompt({'name': 'q',
'type': 'input',
'message': 'well, foo'})
print("f is", f)
return a
And this is the test:
import unittest
from unittest.mock import patch
from Foo import Foo
class TestFoo(unittest.TestCase):
@patch('PyInquirer.prompt', return_value=24)
def test_bar(self):
f = Foo()
a = f.bar()
assert a == 24
if __name__ == '__main__':
unittest.main()
(the real code is obviously more complicated, but this is the essence of the problem). Which manifests itself as:
Error
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
yield
File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 605, in run
testMethod()
File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 1179, in patched
return func(*args, **keywargs)
TypeError: test_bar() takes 1 positional argument but 2 were given
I'm quite confused.
If I omit the patch decorator, the invocation fails with an expected assertion error - the dictionary produced by prompt isn't equal to 24. But if I do provide the decorator, I get the argument mismatch above. And indeed the last line in the stacktrace does show the function "func", which I presume is what the decorator was applied to, is invoked with two arguments... but... why? Can't be the essence of a problem? That only functions with arity of two can be thus patched =)
Upvotes: 0
Views: 398
Reputation: 532303
Your class uses the name Foo.prompt
(because of how you import it), so that's what you need to patch.
class TestFoo(unittest.TestCase):
@patch('Foo.prompt', return_value=24)
def test_bar(self, mock_prompt):
f = Foo()
a = f.bar()
assert a == 24
You also need to add a parameter to test_bar
to receive the patched object, whether or not you plan to use it. If you don't want to do that,
you can move the call to patch
inside the method, using it with a with
statement.
class TestFoo(unittest.TestCase):
def test_bar(self):
with patch('Foo.prompt', return_value=24):
f = Foo()
a = f.bar()
assert a == 24
Upvotes: 3