Unittest Mock - Assert a mock object is not called - python

I am new to unittest and mock in python. I would like to assert a mock is not called.
def test_check_is_available_all_day(self):
create_not_on_leave = Mock()
delete_not_on_leave = Mock()
create_is_not_available = Mock()
for idx, row in self.employee.iterrows():
if row['all_day'] == 1:
if row['is_available'] == 1:
create_not_on_leave()
create_not_on_leave.assert_called()
elif row['is_available'] == 0:
delete_not_on_leave()
create_is_not_available()
How do I assert delete_not_on_leave() is not called. I have tried assert delete_not_on_leave.assert_called() == False but this is gave a error.

use: self.assertEqual(create_not_on_leave.call_count, 0)

Related

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”:

mailoutbox works only if last fixture

If I use the mailoutbox fixture like this, it works:
def test_send_invoices_via_mail_page(user_client, invoice, mailoutbox):
url = reverse(send_invoices_via_mail_page)
response = user_client.get(url)
assert response.status_code == 200
log = LogOfInvoiceMail.objects.get(invoice=invoice)
assert log.success, log.exception
assert log.invoice == invoice
assert log.exception == ''
assert len(mailoutbox) == 1, mailoutbox
But if I use it like this it fails:
def test_send_invoices_via_mail_page(mailoutbox, user_client, invoice):
Error:
> assert len(mailoutbox) == 1, mailoutbox
E AssertionError: []
E assert 0 == 1
Why is the order of the arguments important here?
I am 100% sure that mail.send_mail() gets called in both cases, since I tested it ten times (with ten different ways).

Is there a way to make Mock() return different objects regarding to call arguments?

I have this code to be tested (simplified):
def foo(job):
stop1 = job.stops.get(stop_number=1)
stop1.departed_at = first_scan['scan_date']
stop2 = job.stops.get(stop_number=2)
stop2.pod_time = pod['received_date']
So I do it like this:
job = Mock()
foo(job)
self.assertIsInstance(job.sync_at, datetime.datetime)
self.assertAlmostEqual(job.booked_at, isoformat('2019-10-01T00:00:00'))
self.assertAlmostEqual(job.stops.get(stop_number=1).departed_at, isoformat('2019-10-07T05:24:47'))
self.assertAlmostEqual(job.stops.get(stop_number=2).pod_time, isoformat('2019-10-07T12:00:00'))
The problem is that job.stops.get method return same object with any argument values:
>>> job.stops.get(stop_number=1)
<Mock name='mock.stops.get()' id='140194394261936'>
>>> job.stops.get(stop_number=2)
<Mock name='mock.stops.get()' id='140194394261936'>
>>>
So while testing the above code, I have both job.stops.get(stop_number=1) and job.stops.get(stop_number=2) returning the same output with both departed_at and pod_time attributes set. Because of this, I'm not sure that pod_time was set to stop2 not stop1 and vice versa.
Question is how to make mock return different instances regarding to stop_number value?
You can assign a callable to the side_effect attribute of a Mock object. Make the callable return different objects based on different input arguments:
def mock_get(stop_number):
return {
1: Mock(departed_at='2019-10-07T05:24:47'),
2: Mock(pod_time='2019-10-07T12:00:00')
}[stop_number]
job = Mock()
job.stops.get.side_effect = mock_get
foo(job)
assert job.stops.get(stop_number=1).departed_at == '2019-10-07T05:24:47' # passes
assert job.stops.get(stop_number=2).pod_time == '2019-10-07T12:00:00' # passes

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)

Patching a function using Mock

I have a test suite (using nose, not unittest), and I want to patch a function to return a specific sequence of values for every test in the test class. My first attempt, using a simplified example, was:
#patch('time.clock', MagicMock(side_effects=[1, 2]))
class Tests:
def test_1(self):
assert time.clock() == 1
assert time.clock() == 2
def test_2(self):
assert time.clock() == 1
assert time.clock() == 2
However, the MagicMock instance is only created once, so the second test fails when the side effects run out. I can patch each test method separately, but I don't really want to duplicate the patch decorator over all of them (there are a lot more tests than in this example!) The other way I could do it is to create the patch in the setup code like this:
class Tests:
def setup(self):
self.old_clock = time.clock
time.clock = MagicMock(side_effects=[1, 2])
def teardown(self):
time.clock = self.old_clock
def test_1(self):
assert time.clock() == 1
assert time.clock() == 2
def test_2(self):
assert time.clock() == 1
assert time.clock() == 2
But saving and restoring the original function definition seems like something that Mock should be able to do automatically. Is there another method of doing this that I'm missing? Or is my last example the best way of doing this?
a = (x for x in [1,2])
x = lambda : next(a)
x()
Out: 1
x()
Out: 2
Put your answers into a's list.
Change X for your desired name.
You should just apply the patch to every test, instead of applying it to the class:
class Tests:
#patch('time.clock', MagicMock(side_effects=[1, 2]))
def test_1(self):
assert time.clock() == 1
assert time.clock() == 2
#patch('time.clock', MagicMock(side_effects=[1, 2]))
def test_2(self):
assert time.clock() == 1
assert time.clock() == 2

Categories