tl;dr: I know a code block I am testing with unittest is being executed because of a print statement, but a function directly after the print statement is failing an assert_called check. When running the code, the function is being called and exectued as expected. Unclear why test is failing.
Code in function being tested:
from path.to import deliver_error
def handle_error(ARGS):
if HANDLE_ERROR_BOOL:
print('calling deliver_error')
deliver_error(ARGS)
else:
# do something else
Test code:
class TestSampleRegistration(unittest.TestCase):
def setUp():
# mock deliver_error
mock_deliver_error_patch = patch("path.to.deliver_error", autospec=True)
self.mock_deliver_error = mock_deliver_error_patch.start()
self.addCleanup(mock_deliver_error_patch.stop)
def test_handle_error(self):
main.HANDLE_ERROR_BOOL = True
handle_error(ARGS)
self.mock_deliver_error.assert_called() # point of failure
Assertion failure:
AssertionError: Expected 'deliver_error' to have been called.
Captured stdout:
Captured stdout for test_main.MyTestClass.test_handle_error
calling deliver_error
I KNOW:
HANDLE_ERROR_BOOL is correctly set (print statement executed and showing up in stdout)
deliver_error should be getting called since there is nothing between the print statement and the deliver_error call, and the print statement is being executed
when running the actual code the function is being executed as expected
So why is the assert_called test failing? Help very much appreciated, thank you!
Answering for the sake of others who might see this post:
As per MrBean Bremen's comment, the resolution was to update the mock from
class TestSampleRegistration(unittest.TestCase):
def setUp():
# mock deliver_error
mock_deliver_error_patch = patch("path.to.deliver_error", autospec=True)
to
class TestSampleRegistration(unittest.TestCase):
def setUp():
# mock deliver_error
mock_deliver_error_patch = patch("mymodule.deliver_error", autospec=True)
Related
For instance, every time a test finds
database.db.session.using_bind("reader")
I want to remove the using_bind("reader")) and just work with
database.db.session
using mocker
Tried to use it like this in conftest.py
#pytest.fixture(scope='function')
def session(mocker):
mocker.patch('store.database.db.session.using_bind', return_value=_db.db.session)
But nothing has worked so far.
Code under test:
from store import database
results = database.db.session.using_bind("reader").query(database.Order.id).join(database.Shop).filter(database.Shop.deleted == False).all(),
and I get
AttributeError: 'scoped_session' object has no attribute 'using_bind' as an error.
Let's start with an MRE where the code under test uses a fake database:
from unittest.mock import Mock, patch
class Session:
def using_bind(self, bind):
raise NotImplementedError(f"Can't bind {bind}")
def query(self):
return "success!"
database = Mock()
database.db.session = Session()
def code_under_test():
return database.db.session.using_bind("reader").query()
def test():
assert code_under_test() == "success!"
Running this test fails with:
E NotImplementedError: Can't bind reader
So we want to mock session.using_bind in code_under_test so that it returns session -- that will make our test pass.
We do that using patch, like so:
#patch("test.database.db.session.using_bind")
def test(mock_bind):
mock_bind.return_value = database.db.session
assert code_under_test() == "success!"
Note that my code is in a file called test.py, so my patch call applies to the test module -- you will need to adjust this to point to the module under test in your own code.
Note also that I need to set up my mock before calling the code under test.
I have the following function in a file called my_file.py:
import logging
log = logging.getLogger(__name__)
class MyClass:
def my_func(self):
print("Entered my_func()")
print("log.error = {}".format(log.error))
log.error("Hello World")
When my_func() is run, I see this output:
Entered my_func()
log.error = <bound method ProcessAwareLogger.error of <celery.utils.log.ProcessAwareLogger object at 0x7fd52d4f0d50>>
I want to write a unit-test case to check that whenever my_func() is called, log.error() is called with the argument "Hello World".
So my test case looks like this:
import mock
from my_file import MyClass
#mock.patch("my_file.logging.error")
def test_parse_response_with_error(self, mock_log_error):
m = MyClass()
m.my_func()
mock_log_error.assert_called_once_with("Hello World")
When I run this test case, I get the error: AssertionError: Expected to be called once. Called 0 times. So my patch apparently didn't work. Did I specify the path my_file.logging.error wrong? How can I make this work properly so that the unit-test case passes?
You mocked the wrong thing. log.error creates a bound method that is distinct from logging.error, and that method already has a reference to the "real" logging.error saved before your patch was created.
Instead, mock the error attribute of the Logger instance directly.
#mock.patch.object(my_file.log, 'error'):
def test_it(self, mock_log_error):
m = MyClass()
m.my_func()
mock_log_error.assert_called_once_with("Hello World")
(It's possible that patching logging.error before importing my_file might work.)
So, basically I want to mock a function imported in another class, and for some reason I can't retrieve the mocked result without calling returnvalue of the mock.
This is the setup: one file, one module, one test class. I want to mock functionB() in source.fileB.
source.fileB
def functionB():
print('toto')
source.fileA
from source.fileB import *
def functionA():
print("bar")
return functionB()
Test case
from source.fileA import functionA
from source.fileA import functionB
#mock.patch('source.fileA.functionB')
def test_functionA(functionB_mock):
functionB_mock().returnvalue = "foo"
print(functionB_mock) # prints MagicMock object named functionB
print(functionB_mock.returnvalue) # prints MagicMock object name functionB.returnvalue
print(functionB_mock().returnvalue) #prints "foo"
print(functionA().returnvalue) #executes functionA, prints both "bar" and "foo"
print(functionA()) #executes functionA, prints both "bar" and MagicMock object named functionB()
So every time I try to get the result of the mocked functionB(), I have to use returnvalue. This is driving me nuts as I cannot update functionA() with
return functionB().returnvalue
in order for the rest of the code under test to execute properly.
I must be doing something wrong, but I can't understand what precisely.
There are two problems:
The mock attribute you want is return_value, not returnvalue!
You need to set that attribute on the mock itself, not the result of calling the mock (which is a different mock).
Here's a self-contained (single-file) version of your test code with the fix and some explanatory comments.
import mock
def functionB():
print('toto')
def functionA():
print("bar")
return functionB()
#mock.patch('__main__.functionB')
def test_functionA(functionB_mock):
functionB_mock.return_value = "foo"
# Prints a mock object because that's what functionB_mock is.
print(functionB_mock)
# Prints "foo" because that's what functionB_mock returns.
print(functionB_mock())
# The following two lines would raise AttributeError because
# "foo" isn't a Mock and doesn't have a 'return_value' attribute!
# print(functionB_mock().return_value)
# print(functionA().return_value)
# Executes functionA, prints "bar" and "foo"
print(functionA())
test_functionA()
I'm in trouble replacing a python function from a different module with a TestClass
I'm trying to test a part of my code that contains the function in a module; more in details I would like monkey patch this function.
So, the situation is similar to the following:
Function in the module
def function_in_module():
# do some stuff
return 'ok'
Part of my code that I would like testing
from dir_1.dir_2.dir_3.module_name import function_in_module
class ExampleClass():
def __init__(self):
# do some stuff
self.var_x = function_in_module()
# do some stuff again
Test class
from dir_1.dir_2.dir_3 import module_name
class TestClass(TestCase):
de_monkey = {}
mp = None
def setUp(self):
# save original one
self.de_monkey['function_in_module'] = module_name.function_in_module()
if self.mp is None:
self.mp = MP()
def tearDown(self):
# rollback at the end
module_name.function_in_module = self.de_monkey['function_in_module']
def test_string(self):
module_name.function_in_module = self.mp.monkey_function_in_module
test_obj = ExampleClass()
self.assertEqual(test_obj.var_x, 'not ok')
class MP(object):
#staticmethod
def monkey_function_in_module(self):
return 'not ok'
As the assert statement shows, the expected result is 'not ok', but the result is 'ok'.
I have debugged about this and seems that the different way to call the functions is the reason because this monkey patch doesn't work.
In fact, if I try to call the function in ExampleClass in this way
self.var_x = module_name.function_in_module()
works correctly.
What am I missing? maybe it's a banality but it's driving me crazy
Thank you in advance
Your code under test imports function_in_module and references it directly. Changing the value of module_name.function_in_module has no effect on the code.
You should replace the function directly in the module that contains the code under test, not in the source module.
Note that your life would be easier if you used the mock library, although the question of where to patch would still be the same.
I'm trying to make sure Testme.command() calls bar() on an instance of Dependency but I keep coming up short. I'm running this with python -m unittest tests.test_config and this code lives in tests/test_config.py in my project.
class Dependency():
def bar(self):
""" Do some expensive operation. """
return "some really expensive method"
class Testme():
def __init__(self):
self.dep = Dependency()
def command(self):
try:
self.dep.bar()
return True
except NotImplementedError:
return False
import unittest
from unittest.mock import Mock
class TestTestme(unittest.TestCase):
def test_command(self):
with (unittest.mock.patch('tests.test_config.Dependency')) as d:
d.bar.return_value = 'cheap'
t = Testme()
t.command()
d.bar.assert_called_once_with()
When I run it, it fails like bar() never got called: AssertionError: Expected 'bar' to be called once. Called 0 times.
How should I test that Testme().command() calls Dependency().bar()?
Try printing by doing
print self.dep.bar()
and
print d.bar.assert_called_once_with()
See if it outputs the correct value of "some really expensive method"