简体   繁体   中英

python unittest mocking / patching

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 =)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM