Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pytest works with old mock, but not unittest.mock

I'm porting some code from Python 2 to 3, and py.test isn't playing well with the patch decorator from unittest.mock. When I use the patch decorator to pass a mock into the arguments of a test function, py.test instead interprets that argument to be a fixture, and is unable to set up the test.

Here's a contrived example that hopefully illuminates the problem:

@patch('my_module.my_func')
def test_my_func(mock_func):
    mock_func()
    mock_func.assert_called_once_with()

After running py.test, the error message would look like:

E       fixture 'my_func' not found
>       available fixtures: cache, capfd, capsys, doctest_namespace, monkeypatch, pytestconfig, record_xml_property, recwarn, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

This is the only scenario under which this failure occurs. If I explicitly call the test (i.e. run test_my_func()), no error. If I patch my_func using either of the other patching techniques, no error. If I import patch from mock instead of unittest.mock, no error.

It's only while running my tests using py.test, using unittest.mock, and patching using the decorator when this occurs.

I'm running Python 3.4.5.

like image 944
James Kelleher Avatar asked Aug 26 '16 15:08

James Kelleher


2 Answers

Yes, mock decorators are not supported. It's not such bad -- changing function signature by decorator appliance is considered as bad idea. But you still may use with mock.patch(...) syntax.

Also as an option there is pytest-mock plugin with pretty clean api for mocking:

def test_foo(mocker):
    # all valid calls
    mocker.patch('os.remove')
    mocker.patch.object(os, 'listdir', autospec=True)
    mocked_isfile = mocker.patch('os.path.isfile')
like image 127
Andrew Svetlov Avatar answered Oct 24 '22 15:10

Andrew Svetlov


There was a pytest issue that now seems to be solved in a newer version of pytest: https://github.com/pytest-dev/pytest/pull/3206/commits/b6166dccb4d2b48173aa7e7739be52db9d2d56a0

Basically, if you had mock installed, this would fail. You can verify by uninstalling mock and running the test again.

If you really need that version of pytest, you can get the mock using with patch(..) inside the function.

like image 25
fersarr Avatar answered Oct 24 '22 15:10

fersarr