I have the following code:
my_module.py
def my_func(number):
def nested_func(value):
'''
Doing some calculation
'''
return result
output = []
for i in range(number):
res = nested_func(i)
output.append(res)
return output
I'm using pytest with pytest-mock and mocker as a fixture in test_my_module.py
test_my_module.py
def test_my_module(mocker):
expected_res = [1, 1, 1]
mocker.patch('nested_func', return_value=1)
from my_module import my_func
assert my_func(3) == expected_res
But when I run in py.test I got an error:
TypeError: Need a valid target to patch. You supplied: 'nested_func'
Is there any way to mocker.patch functions\methods, which are not visible in testing module and located as nested in that functions, I want to test?
As a follow up to #MrBean Bremen, I think a work around is to define nested_func outside of my_func and call it within my_func
def nested_func(value):
result = value + 2
return result
def my_func(number):
output = []
for i in range(number):
res = nested_func(i)
output.append(res)
return output
Your test_my_module
from my_module import my_func
def test_my_module(mocker):
expected_res = [1, 1, 1]
mocker.patch('my_module.nested_func', return_value=1)
assert my_func(3) == expected_res
Related
I am trying to mock a bigtable call in my unit test by declaring fixtures like so:
#pytest.fixture()
def bigtableMock():
bigtableMock = Mock(spec=google.cloud.bigtable.table.Table)
yield bigtableMock
#pytest.fixture()
def bigtableInstanceMock(bigtableMock):
bigtableInstanceMock = Mock(spec=google.cloud.bigtable.instance.Instance)
bigtableInstanceMockAttrs = {'table': bigtableMock}
bigtableInstanceMock.configure_mock(**bigtableInstanceMockAttrs)
yield bigtableInstanceMock
#pytest.fixture()
def myDao(bigtableInstanceMock):
yield MyDao(bigtableInstanceMock)
I mock the read_rows function like so:
def mockReadRowsFuncWith1Dto(testDto):
mockTableRowData = {}
mockTableRowData['columnFamily'] = asDict(testDto)
rowDataMock = MagicMock()
rowDataMock.__iter__.return_value = [mockTableRowData]
rowDataMock.__len__ = 1
def mockReadRowsFunc(startKey, endKey, limit, end_inclusive):
return rowDataMock
return mockReadRowsFunc
When I call my test function:
def test_read_table(
myDao,
testDto,
bigtableMock
):
bigtableMock.read_rows = mockReadRowsFuncWith1Dto(testDto)
samp = bigtableMock.read_rows(
startKey="asdf",
endKey="sadf",
limit=1,
end_inclusive=True
)
print(f"\test data {samp}")
myDao.readTable(...)
Inside myDao.readTable I call read_rows like so:
tableRows: PartialRowData = self.table.read_rows(
start_key=startKey,
end_key=endKey,
limit=10,
end_inclusive=True
)
However, I do not get the magicMock return that I expect inside readTable, tableRows:<Mock name='mock.table().read_rows()' id='4378752480'>, whereas in the test function I can print out the Magic mock: test data <MagicMock id='4413191168'>. Regardless of the print statement or not, I can never invoke the correct mocked read_rows function. What am I doing wrong?
The problem in my case was that the fixture for bigtableMock was different between test_read_table and the fixture for myDao. I modified my test cases to include the table mocking inside the bigtableMock like so:
#pytest.fixture(read_row_data, mock_append_row)
def bigtableMock():
bigtableMock = Mock(spec=google.cloud.bigtable.table.Table)
bigtableMock.read_rows.return_value = [read_row_data]
bigtableMock.append_row.return_value = mock_append_row
yield bigtableMock
I would like to mock some imported class methods and module functions for my unit tests. I tried several ways to define the mocked values but I don't understand why they are not taken into account.
I wrote some tests following the advices in Python Mocking a function from an imported module.
Here is a piece of code representing the application to test:
from services import myModule1
from services.spec1 import importedClass
class myClass(object):
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
self.param3 = 0
self.param4 = 0
self.myMethod()
def myMethod(self):
newVar = importedClass()
self.param3 = newVar.meth1(self.param2)
calcParam = myModule1.methodMod1(self.param1)
self.param4 = calcParam["keyParam3"]
I would like to unit test myMethod and I need to mock importedClass and myModule1.methodMod1().
Here is a new piece of code that I tried for the tests (previous attempts below):
import unittest
from unittest.mock import patch
from my_module import myClass
class test_myClass(unittest.TestCase):
#patch('my_module.importedClass')
#patch('my_module.myModule1')
def test_myMethod(self, mock_mod1, mock_class):
mock_mod1.methodMod1.return_value = {"keyParam3": 5, "keyParam4": 7}
mock_class.meth1.return_value = 2
test_parameters = (0, 0)
test_res = myClass(*test_parameters)
self.assertEqual(test_res.param3, 2)
self.assertEqual(test_res.param4, 5)
if __name__ == '__main__':
unittest.main()
The mocking has no error but the mocked values are not taken into account.
Previous attempts
What I tried for each of them, using 2 different approaches:
import unittest
from unittest.mock import Mock, patch
from my_module import myClass
import services
class test_myClass(unittest.TestCase):
def setUp(self):
services.spec1 = Mock()
services.spec1.importedClass.meth1.return_value = 2
#patch('services.myModule1')
def test_myMethod(self, my_mock):
my_mock.methodMod1.return_value = {"keyParam3": 5, "keyParam4": 7}
test_parameters = (0, 0)
test_res = myClass(*test_parameters)
self.assertEqual(test_res.param3, 2)
self.assertEqual(test_res.param4, 5)
if __name__ == '__main__':
unittest.main()
The result is that the calculated attributes are not updated and still 0 - so test fails.
I also tried with services = Mock() and defined return values for each part, to regroup each mock in setUp method or in a #patch, but nothing worked.
I also tried with my_module.spec1 = Mock(), to make the function global, or even self.spec1 = Mock() to make it very local to the test's context (if I understood correctly the differences, this is something I'm not really sure neither) but nothing worked.
To mock just the method:
class test_myClass(unittest.TestCase):
# #patch('my_module.importedClass') # Change this
#patch('my_module.importedClass.meth1') # to this
#patch('my_module.myModule1')
# def test_myMethod(self, mock_mod1, mock_class): # Change this
def test_myMethod(self, mock_mod1, mock_class_meth1): # to this
mock_mod1.methodMod1.return_value = {"keyParam3": 5, "keyParam4": 7}
# mock_class.meth1.return_value = 2 # Change this
mock_class_meth1.return_value = 2 # to this
test_parameters = (0, 0)
test_res = myClass(*test_parameters)
self.assertEqual(test_res.param3, 2)
self.assertEqual(test_res.param4, 5)
To mock the class and its method:
https://docs.python.org/3/library/unittest.mock-examples.html#mocking-classes
class test_myClass(unittest.TestCase):
#patch('my_module.importedClass')
#patch('my_module.myModule1')
def test_myMethod2(self, mock_mod1, mock_class):
mock_mod1.methodMod1.return_value = {"keyParam3": 5, "keyParam4": 7}
# mock_class.meth1.return_value = 2 # Change this
mock_class_instance = mock_class.return_value # to these
mock_class_instance.meth1.return_value = 2 # two lines
test_parameters = (0, 0)
test_res = myClass(*test_parameters)
self.assertEqual(test_res.param3, 2)
self.assertEqual(test_res.param4, 5)
Let's say I have the following python files:
# source.py
def get_one():
return 1
# file1.py
from source import get_one
def func1():
return get_one()
# file2.py
from source import get_one
def func2():
return get_one()
# script.py
from file1 import func1
from file2 import func2
def main(a, b):
count = 0
for _ in range(a):
count += func1()
for _ in range(b):
count += func2()
return count
I know I can mock out get_one() in main.py using the following setup:
def test_mock():
with (
patch("file1.get_one") as mock1,
patch("file2.get_one") as mock2,
):
main(2, 3)
assert mock1.call_count + mock2.call_count == 5
However, this gets increasingly verbose and hard to read if get_one() needs to be mocked out in many files. I would love to be able to mock out all of its locations in a single mock variable. Something like:
# this test fails, I'm just showing what this ideally would look like
def test_mock():
with patch("file1.get_one", "file2.get_one") as mock:
main(2, 3)
assert mock.call_count == 5
Is there anyway to do this or do I need to use multiple mocks?
Note, I know I can't mock where the function is defined, e.g. patch("source.get_one").
patch accepts new as the object to patch the target with:
def test_mock():
with (
patch("file1.get_one") as mock,
patch("file2.get_one", new=mock),
):
main(2, 3)
assert mock.call_count == 5, mock.call_count
You can write a helper context manager:
import contextlib
from unittest.mock import DEFAULT, patch
#contextlib.contextmanager
def patch_same(target, *targets, new=DEFAULT):
with patch(target, new=new) as mock:
if targets:
with patch_same(*targets, new=mock):
yield mock
else:
yield mock
Usage:
def test_mock():
with patch_same("file1.get_one", "file2.get_one") as mock:
main(2, 3)
assert mock.call_count == 5
A possible workaround: add a level of indirection in source.py so that get_one has a dependency that you can patch:
def get_one():
return _get_one()
def _get_one():
return 1
and now you can do this in your test:
from script import main
from unittest.mock import patch
def test_mock():
with patch("source._get_one") as mock1:
main(2, 3)
assert mock1.call_count == 5
I am adding testing to a pipeline project, code is already written and in production so it cannot be changed to accommodate the tests.
In simplest terms, if I have a function like so:
def other_foo():
return 1
def foo():
res = other_foo()
return res
In practicality, the other_foo call will return a variety of responses, but for testing, I want to create a fixed response to test foo.
So in my test I want to create a fixed response to other_foo of 2. and my test evaluation to be something like:
def test_foo():
# some mocking or nesting handle here for other_foo
res = foo()
assert res == 2
Use the patch decorator from unitest.mock and patch your module local variable.
from your.module import foo
from unitest.mock import patch
#patch('your.module.other_foo')
def test_foo(mock_other_foo):
mock_other_foo.return_value = 3
assert foo() == 3
mock_other_foo.return_value = 42
assert foo() == 42
You can find more information here and there.
I have the following test code to test Decorator.
#mock.patch('a.b.c.KafkaProducer')
def test_1(self, mocked):
decorator = Decorator(....)
#decorator()
def test():
return 42
test()
start_time = ???
v = {'type': 'batch', 'start_time': start_time.isoformat()}
mocked.return_value.send.assert_called_once_with(value=v)
However, the test always fail because Decorator calls mocked with dictionary parameter with property of start_time assigned to datetime.now(). Is it a way to compare everything except start_time? Or any other way to test the call?
Two practical approaches:
freeze time using https://pypi.org/project/freezegun/
import datetime
from freezegun import freeze_time
from unittest.mock import patch
import my_library
NOT_NOW = datetime.datetime.now()
#freeze_time("2020-01-01")
#patch("my_library.helper")
def test_foo(_helper):
my_library.under_test(NOT_NOW)
# kinda auto-magic
_helper.assert_called_once_with(datetime.datetime.now())
# or more explicitly
_helper.assert_called_once_with(datetime.datetime(2020, 1, 1))
or, evaluate arguments manually
#patch("my_library.helper", return_value=42)
def test_bar(_helper):
my_library.under_test(NOT_NOW)
assert _helper.call_count == 1
assert _helper.call_args[0][0]
assert _helper.call_args[0][0] != NOT_NOW