I want to write a test for "A" function which calls another "B" function in it. B function looks like this:
def Bfuncion(self, city: Optional[str], name: Optional[str]):
in A function I use B function two times, first time I use it in this way:
cities = self.Bfunction(name=None, city="ny", page=page)
and the second time in this way:
cities = self.Bfunction(name="Tom", city=None, page=page)
Now I want to write a test of A function, I would try this if there was only one use of B function:
mocker.patch(
"Path.To.My.Function",
return_value=[
{"someReturnValue"},
{"someReturnValue"},
{"someReturnValue"},
],
How do I write call mocker()
, as I use B function with different arguments in each call.
CodePudding user response:
Use the side_effect
keyword argument, not the return_value
keyword argument.
>>> from unittest.mock import Mock
>>> m = Mock(return_value=[1,2,3])
>>> m()
[1, 2, 3]
>>> m = Mock(side_effect=[1,2,3])
>>> m()
1
>>> m()
2
>>> m()
3
(patch
, of course, simply passes keyword arguments it does not itself recognize to Mock
to configure the object that is used by the patched name.)
This requires you to know ahead of time the order of calls that will be made. If you need more flexibility, patch the name with a custom function that behaves the way you want, instead of a Mock
object.
def my_func(self, name, city, page):
...
mocker.patch(
"Path.To.My.Function",
new=my_func
)
CodePudding user response:
I try to suggest you a solution for your test; I don't know if it is suite for your need because I have tried to guess some details that you have omitted in your question.
I suppose that your production code is contained in a file called functions.py
and the content of functions.py
is the following:
from typing import Optional
class MyClass:
def Bfunction(self, city: Optional[str], name: Optional[str]):
return city
def Afunction(self):
cities = self.Bfunction(name=None, city="ny", page='page')
print(cities)
cities = self.Bfunction(name="Tom", city=None, page='page')
print(cities)
Note that in functions.py
:
- I have defined a class because I have seen that your definition of the
Bfunction
contains theself
argument. - The
Afunction
executes the two calls ofBfunction
that you have write in your question.
The test file (which doesn't use pytest
but only the module unittest
) is the following:
import unittest
from unittest import mock
import functions
class MyTestCase(unittest.TestCase):
def test_something(self):
sut = functions.MyClass()
with mock.patch.object(sut, 'Bfunction') as mock_b:
# set values returned by Bfunction in the first and in the second call
mock_b.side_effect = ['cityA', 'cityB']
sut.Afunction()
# here I verify that Bfunction is called 2 times
self.assertEqual(2, mock_b.call_count)
mock_b.assert_called_with(city=None, name='Tom', page='page')
mock_b.assert_called_with(name="Tom", city=None, page='page')
if __name__ == '__main__':
unittest.main()
The output of the test file execution is:
cityA
cityB
.
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK
The output showes:
Afunction
calls exactly two times theBfunction
- the test verify the arguments passed to
Bfunction
- the presence of
cityA
andcityB
in the output show you how to select different values returned byBfunction
(you have to useside_effect
and notreturn_value
).
I hope that this answer is useful for you.