Pytest with mock/pytest-mock - python

For some reason I cannot get mock.patch to work in any scenario when using Pytest. It simply doesn't do the patching. Am I using it incorrectly or is something messed up with my configuration?
base.py
def foo():
return 'foo'
def get_foo():
return foo()
test_base.py
import pytest
import mock
from pytest_mock import mocker
from base import get_foo
#mock.patch('base.foo')
def test_get_foo(mock_foo):
mock_foo.return_value = 'bar'
assert get_foo() == 'bar'
def test_get_foo2(mocker):
m = mocker.patch('base.foo', return_value='bar')
assert get_foo() == 'bar'
def test_get_foo3():
with mock.patch('base.foo', return_value='bar') as mock_foo:
assert get_foo() == 'bar'
pytest results
============================================================= test session starts =============================================================
platform linux2 -- Python 2.7.13, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /projects/git/ABC/query, inifile:
plugins: mock-1.6.0
collected 13 items
test_base.py .....FFF.....
================================================================== FAILURES ===================================================================
________________________________________________________________ test_get_foo _________________________________________________________________
mock_foo = <MagicMock name='foo' id='140418877133648'>
#mock.patch('base.foo')
def test_get_foo(mock_foo):
mock_foo.return_value = 'bar'
> assert get_foo() == 'bar'
E AssertionError: assert 'foo' == 'bar'
E - foo
E + bar
test_base.py:67: AssertionError
________________________________________________________________ test_get_foo2 ________________________________________________________________
mocker = <pytest_mock.MockFixture object at 0x7fb5d14bc210>
def test_get_foo2(mocker):
m = mocker.patch('base.foo', return_value='bar')
> assert get_foo() == 'bar'
E AssertionError: assert 'foo' == 'bar'
E - foo
E + bar
test_base.py:71: AssertionError
________________________________________________________________ test_get_foo3 ________________________________________________________________
def test_get_foo3():
with mock.patch('base.foo', return_value='bar') as mock_foo:
> assert get_foo() == 'bar'
E AssertionError: assert 'foo' == 'bar'
E - foo
E + bar
test_base.py:75: AssertionError

The problem was due to the relationship between my import specification and PATH variable. If I specified the entire path in the patch argument, like: #mock.patch('<PROJECT_ROOT>.<SUBPACKAGE>.base.foo') where PATH had the parent directory of as an entry, then it worked. I don't know why it wasn't throwing an import error if it wasn't finding base.foo. And if it wasn't finding it, I don't understand how the scope was different.

Related

pytest pass cmd line options to test scripts but not to test function

my test_sample.py is like:
import pytest
a,b = myclass('cmdopts').get_spec()
def gen_args(a, b):
for i in a:
for j in b:
yield (i,j)
#pytest.mark.parametrize('a,b', gen_args(a,b))
def test_c1(a, b):
assert a == b
my question is how can I pass cmdopts to the test script, not to the test_c1 function?
pytest.mark.parametrize is not intended to be used in this way.
with pytest_addoption of pytest you can inject yours a, b parameters using metafunc.parametrize
using this technique allow you to set also parameters in environment variables.
conftest.py
def pytest_addoption(parser):
parser.addoption("--a", action="store")
parser.addoption("--b", action="store")
def pytest_generate_tests(metafunc):
for par_name, par_value in (
('a',metafunc.config.option.a),
('b',metafunc.config.option.b)
):
if par_name in metafunc.fixturenames and par_value:
metafunc.parametrize(par_name, [par_value])
test_sample.py
def test_c1(a, b):
assert a == b
CLI
$ pytest test_sample.py --a 42 --b 42
collected 1 item
test_sample.py . [100%]
= 1 passed in 0.01s =
$ pytest test_sample.py --a 42 --b 24
collected 1 item
test_sample.py F [100%]
= FAILURES =
_ test_c1[42-24] _
a = '42', b = '24'
def test_c1(a, b):
> assert a == b
E AssertionError: assert '42' == '24'
E - 24
E + 42
test_sample.py:2: AssertionError
================================================================================== short test summary info ==================================================================================
FAILED test_sample.py::test_c1[42-24] - AssertionError: assert '42' == '24'
===================================================================================== 1 failed in 0.07s
Something similar here: How to pass arguments in pytest by command line

pytest unable to mock the same module multiple times [duplicate]

This question already has answers here:
Mock patching from/import statement in Python
(3 answers)
Closed 1 year ago.
I'm tring to use mock to test a specific function, for some reasons it seems that I can't mock twice the same module and I don't understand why
a.py
def a():
return "ok"
b.py
from sandbox.tests.a import a
def b(la):
for i in la:
a()
return "b"
def c():
a()
return "c"
What I want to test is the amount of calls of a are made, so in my test I do :
from mock import patch
#patch("sandbox.tests.a.a", return_value="mocked")
def test_b(mock):
from sandbox.tests.b import b
b(["1", "2"])
assert mock.call_count == 2
#patch("sandbox.tests.a.a", return_value="mocked2")
def test_b_again(mock):
from sandbox.tests.b import c
c()
assert mock.call_count == 1
If I run 1 test it works but when I run the 2 tests together I have this error :
E AssertionError: assert 0 == 1
E + where 0 = <Mock name='test_2' id='4360227664'>.call_count
Surprisingly if I print the output of the mock in each function b and c, the mock has the same ID :
a <MagicMock name='a' id='4358021024'> # function b
a <MagicMock name='a' id='4358021024'> # function c
I also tried to put a name on the mock but it stills gives the same id
#patch("sandbox.tests.a.a")
def test_b(mock):
mock = Mock(name="test_1", return_value="test_1")
from sandbox.tests.b import b
b(["1", "2"])
assert mock.call_count == 2
#patch("sandbox.tests.a.a")
def test_b_again(mock):
mock = Mock(name="test_2", return_value="test_2")
from sandbox.tests.b import c
c()
assert mock.call_count == 1
Is there an equivalent of jest.resetModules() or something so I can mock twice the same module ?
Thanks
The solution is to patch a within the context of module b, rather than trying to patch sandbox.tests.a 'directly'. This is necessary because module b imports a only once, rather than in each of functions b and c.
Instead, patch sandbox.tests.b.a - i.e the 'instance' of a which is being used by module b:
#patch("sandbox.tests.b.a", return_value="mocked")
def test_b(self, mock):
from sandbox.tests.b import b
b(["1", "2"])
assert mock.call_count == 2
#patch("sandbox.tests.b.a", return_value="mocked2")
def test_c(self, mock):
from sandbox.tests.b import c
c()
assert mock.call_count == 1

Patching a method of a class that is already patched

I'm trying to patch a class and its method, this is an example that what I'm trying to do:
class Car:
def __init__(self, color):
self.color = color
def show_color(self):
return self.color
I have this class and I want to patch the class, and its method separately, I didn't create a fake class, because in my case the class is complex, so I want the class to be created and then just patch a method of some that has the class, I'm trying to do this:
import example
def test_example(
mocker
):
mocker.patch("example.Car")
mocker.patch("example.Car.show_color").return_value = "red"
c = example.Car("blue")
assert c.show_color() == "red"
Also, I tried to do something like this:
import example
def test_example(
mocker
):
mocker.patch("example.Car").return_value = mocker.create_autospec(
example.Car,
show_color = "red"
)
c = example.Car("blue")
assert c.show_color() == "red"
In the two cases, I got this error:
========================================================================================== FAILURES ==========================================================================================
________________________________________________________________________________________ test_example ________________________________________________________________________________________
mocker = <pytest_mock.plugin.MockerFixture object at 0x102281bb0>
def test_example(
mocker
):
mocker.patch("example.Car")
mocker.patch("example.Car.show_color").return_value = "red"
c = example.Car("blue")
> assert c.show_color() == "red"
E AssertionError: assert <MagicMock name='Car().show_color()' id='4331364896'> == 'red'
E + where <MagicMock name='Car().show_color()' id='4331364896'> = <MagicMock name='Car().show_color' id='4331344512'>()
E + where <MagicMock name='Car().show_color' id='4331344512'> = <MagicMock name='Car()' id='4331304944'>.show_color
test_mocking.py:21: AssertionError
================================================================================== short test summary info ===================================================================================
FAILED test_mocking.py::test_example - AssertionError: assert <MagicMock name='Car().show_color()' id='4331364896'> == 'red'
===================================================================================== 1 failed in 0.06s ======================================================================================
I'm patching the method, because I have another method from another class that I want to test
mocker.patch itself returns the mock, which you can then interact with:
def test_example(mocker):
Car = mocker.patch("example.Car")
Car.return_value.show_color.return_value = "red"
c = example.Car("blue")
assert c.show_color() == "red"
Alternatively, patch accepts **kwargs which you can use to configure sub-mocks:
def test_example_alternative(mocker):
config = {"return_value.show_color.return_value": "red"}
mocker.patch("example.Car", **config)
c = example.Car("blue")
assert c.show_color() == "red"
You’re patching with:
show_color = "red"
But your assert is trying to call show_color as if it were a function
if c.show_color() == “red”:
which is doomed to fail, maybe you should test:
if c.show_color == “red”:

Cannot mock method of mocked object? call_count is 0 in pytest

I have the following function in the file myfile.py:
#myfile.py
import psutil
class RunnableObject:
def run(self):
parent = psutil.Process()
print(parent)
children = parent.children(recursive=True)
print(children)
Then I have a unit test where runnable_object is an instance of the RunnableObject class which I setup using a pytest fixture.
#patch("myfile.psutil")
def test_run_post_request(self, psutil_, runnable_object):
runnable_object.run()
assert psutil_.Process.call_count == 1
assert psutil_.Process.children.call_count == 1
When I run my test however I get the following error:
assert psutil_.Process.call_count == 1
> assert psutil_.Process.children.call_count == 1
E assert 0 == 1
E +0
E -1
-1
tests/unit/test_experiment.py:1651: AssertionError
My stdout:
<MagicMock name='psutil.Process()' id='3001903696'>
<MagicMock name='psutil.Process().children()' id='3000968624'>
I also tried to use #patch.object(psutil.Process, "children") as well as#patch("myfile.psutil.Process") and #patch("myfile.psutil.Process.children") but that gave me the same problem.
children is the property of the return value of psutil.Process(). NOT the property of the Process method.
So the correct assertion is:
test_myfile.py:
from unittest import TestCase
import unittest
from unittest.mock import patch
from myfile import RunnableObject
class TestRunnableObject(TestCase):
#patch("myfile.psutil")
def test_run_post_request(self, psutil_):
runnable_object = RunnableObject()
runnable_object.run()
assert psutil_.Process.call_count == 1
assert psutil_.Process().children.call_count == 1
if __name__ == '__main__':
unittest.main()
test result:
<MagicMock name='psutil.Process()' id='4394128192'>
<MagicMock name='psutil.Process().children()' id='4394180912'>
.
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK
Name Stmts Miss Cover Missing
-------------------------------------------------------------------------
src/stackoverflow/67362647/myfile.py 7 0 100%
src/stackoverflow/67362647/test_myfile.py 13 0 100%
-------------------------------------------------------------------------
TOTAL 20 0 100%

pytest-mock assert_called_with failed for class function

I am planning to use pytest and pytest-mock for validating the Python code. Being a newbie, wrote a sample code to validate the mock on class and seeing failure. I am wondering what went wrong.
src/main.py
class Main(object):
def __init__(self, my_var=None):
self.var = my_var
def internal_func(self, var=10):
my_var = var + 20
return my_var
def test_func(self):
val = self.internal_func(20)
return val + 40
tests/test_main.py
import pytest
from pytest_mock import mocker
from src.main import Main
def new_func(cls, *args, **kwargs):
return 2
def test_main_mock(mocker):
mocker.patch.object(Main, 'internal_func')
val = Main().test_func()
assert Main.internal_func.assert_called_with(20)
It fails with the following error
======================================================================================== FAILURES ========================================================================================
_____________________________________________________________________________________ test_main_mock _____________________________________________________________________________________
mocker = <pytest_mock.MockFixture object at 0x7f34f490d8d0>
def test_main_mock(mocker):
mocker.patch.object(Main, 'internal_func')
main = Main()
val = main.test_func()
# assert val == 80
> assert Main.internal_func.assert_called_with(20)
E AssertionError: assert None
E + where None = <bound method MagicMock.wrap_assert_called_with of <MagicMock name='internal_func' id='139865418160784'>>(20)
E + where <bound method MagicMock.wrap_assert_called_with of <MagicMock name='internal_func' id='139865418160784'>> = <MagicMock name='internal_func' id='139865418160784'>.assert_called_with
E + where <MagicMock name='internal_func' id='139865418160784'> = Main.internal_func
tests/test_main.py:13: AssertionError
The return_value or side_effect must be set before the patched func take effect
def test_main_mock(mocker):
# mock internal_func of class Main
mocked_internal_func = mocker.patch.object(Main, 'internal_func')
# assign return_value or side_effect
mocked_internal_func.return_value = -10
# class instance
ma = Main()
val = ma.test_func()
assert ma.internal_func.assert_called_with(20)
Correction of mistake, the assert should not be used together with assert_called_with, they are independent assert.
assert val == 30
mocked_internal_func.assert_called
ma.internal_func.assert_called_with(20)
mocked_internal_func.assert_called_with(20)

Categories