The standard way to do this kind of test is to mock the entire class, like so:
def test_bar(mocker):
mock_foo = mocker.MagicMock(name='Foo')
mocker.patch('test.Foo', new=mock_foo)
mock_foo.return_value.x = 2
assert bar() == 3
mock_foo.assert_called_once_with(1)
So in this case, you mock the entire Foo
class.
Then, there is this syntax mock_foo.return_value.x = 2
: where mock_foo.return_value
simply means the return object when calling Foo(1)
- which is your object. Since we mocked the entire class - the __init__
method does nothing - so you need to set the x
attribute on your own.
Also note the mock_foo.assert_called_once_with(1)
- which checks that Foo(1)
was called with the right parameter.
p.s.
To simplify this kind of mocking, I created a pytest fixture called pytest-mock-generator. You can use it to help you create the mocks and asserts.
You start with using the mg
fixture to analyze your bar
method so it locates the relevant mocks for you:
def test_bar(mocker, mg):
mg.generate_uut_mocks(bar)
When this test method is executed, it generates the following code (prints it to the console and copies it to your clipboard for quick usage):
# mocked dependencies
mock_Foo = mocker.MagicMock(name='Foo')
mocker.patch('test.Foo', new=mock_Foo)
You then modify the test function and execute the bar method and use the generate_asserts
capability:
def test_bar(mocker, mg):
# mocked dependencies
mock_Foo = mocker.MagicMock(name='Foo')
mocker.patch('test.Foo', new=mock_Foo)
bar()
mg.generate_asserts(mock_Foo)
This gives you the following output:
assert 1 == mock_Foo.call_count
mock_Foo.assert_called_once_with(1)
mock_Foo.return_value.x.__add__.assert_called_once_with(1)
You don't need most of it, but you can keep the second line for your assert and the modify the third line so x
has the right value:
def test_bar(mocker):
mock_foo = mocker.MagicMock(name='Foo')
mocker.patch('test.Foo', new=mock_foo)
mock_foo.return_value.x = 2
assert bar() == 3
mock_foo.assert_called_once_with(1)