I am having hard times with unittest mock and patch. I'd like to test a specific class and change some attributes in it.
I think that I have a path problem but can't figure how to resolve it.
#lib.inventory.py
class Inventory(object):
def __init__(self):
self.db = "12"
def do_stuff(self):
return "ok"
#test.py
import unittest
from mock import patch
import time
from lib.inventory import Inventory
#test_case.py
class MyTest(unittest.TestCase):
#patch('lib.inventory.Inventory')
def test_retrieve_project_id(self,mock_inventory):
print "####################"
print Inventory
print mock_inventory
print "####################"
When I run this test I should see that both Inventory and mock_inventory objects points to the same MagickMock Object. But it isn't the case :
####################
<class 'lib.inventory.Inventory'>
<MagicMock name='Inventory' id='140594977874320'>
####################
Could you tell me what I am doing wrong ?? Maybe I have misanderstood mock and patch concept ?
Thank you
Related
I have the following structure:
# create.py
import sshHandler
class Create:
def __init__(self):
self.value = sshHandler.some_method()
# sshHandler.py
def some_method():
return True
If I kow try to patch sshHandler.some_method it will not work as expected
from unittest import TestCase
from unittest.mock import patch
import create
class TestCreate(TestCase):
#patch("sshHandler.some_method")
def test_create(self, mock_ssh):
mock_ssh.return_value = False
c = create.Create()
# c.value = True but should be false
The result I am looking for is that some_method would be patched in create as well (and return false). If I just call some_method in the context of test_create it works as expected. How do I fix the patch so that it is also active in the Create class when accessing sshHandler?
I saw this question Why python mock patch doesn't work?, but couldn't solve my problem with the information given there.
You've patched the wrong module. Instead patch the sshHandler.some_method patch create.sshHandler.some_method. You must patch the object of module you're handling.
Does pytest provides functionality like unittest.mock to check if the mock was actually called once(or once with some parameter)?
Sample Source code:
my_package/my_module.py
from com.abc.validation import Validation
class MyModule:
def __init__(self):
pass
def will_call_other_package(self):
val = Validation()
val.do()
def run(self):
self.will_call_other_package()
Sample test code for the above source code:
test_my_module.py
import pytest
from pytest_mock import mocker
from my_package.my_module import MyModule
#pytest.fixture
def mock_will_call_other_package(mocker):
mocker.patch('my_package.my_module.will_call_other_package')
#pytest.mark.usefixtures("mock_will_call_other_package")
class TestMyModule:
def test_run(self):
MyModule().run()
#check `will_call_other_package` method is called.
#Looking for something similar to what unittest.mock provide
#mock_will_call_other_package.called_once
If you want to use a fixture that does the patching, you can move the patching into a fixture:
import pytest
from unittest import mock
from my_package.my_module import MyModule
#pytest.fixture
def mock_will_call_other_package():
with mock.patch('my_package.my_module.will_call_other_package') as mocked:
yield mocked
# the mocking will be reverted here, e.g. after the test
class TestMyModule:
def test_run(self, mock_will_call_other_package):
MyModule().run()
mock_will_call_other_package.assert_called_once()
Note that you have to use the fixture parameter in the test. Just using #pytest.mark.usefixtures will not give you access to the mock itself. You can still use it to be effective in all tests in the class, if you don't need to access the mock in all tests (or use autouse=True in the fixture).
Also note that you don't need pytest-mock here - but as mentioned by #hoefling, using it makes the fixture better readable, because you don't need the with clause :
#pytest.fixture
def mock_will_call_other_package(mocker):
yield mocker.patch('my_package.my_module.will_call_other_package')
As an aside: you don't need to import mocker. Fixtures are looked up by name, and available automatically if the respective plugin is installed.
You could try this:
import pytest
from my_package.my_module import MyModule
def test_run(mocker):
mocker.patch('my_package.my_module.will_call_other_package')
MyModule().run()
mock_will_call_other_package.assert_called_once()
First of all, you may not need the burden of an external library such as pytest_mock, because pytest already got you covered using the integration with unittest.
You also do not need to use the usefixtures because whenever you need a fixture, you just receive it in your test method.
An ideal scenario based on your own code would look similar to this:
import pytest
from unittest.mock import patch
from com.abc.validation import Validation
class MyModule:
def __init__(self):
pass
def will_call_other_package(self):
val = Validation()
val.do()
def run(self):
self.will_call_other_package()
#pytest.fixture
def call_other_module():
with patch("my_package.my_module.MyModule.will_call_other_package") as _patched:
yield _patched
class TestMyModule:
def test_run_will_call_other_package(self, call_other_module):
call_other_module.assert_not_called()
obj = MyModule()
call_other_module.assert_not_called()
obj.run()
call_other_module.assert_called_once()
And also if you want to make sure that you did infact patch the target MyModule.will_call_other_package, modify your test like this:
class TestMyModule:
def test_run_will_call_other_package(self, call_other_module):
call_other_module.assert_not_called()
obj = MyModule()
call_other_module.assert_not_called()
obj.run()
call_other_module.assert_called_once()
assert False, (MyModule.will_call_other_package, call_other_module)
And you'll see something similar to this:
AssertionError: (<MagicMock name='will_call_other_package' id='140695551841328'>, <MagicMock name='will_call_other_package' id='140695551841328'>)
As you can see the id of both objects are the same, confirming our experiment was successful.
Example abc.py:
from pack.def import Def
class Abc(object):
def f(self):
return Def().response()
Example test_abc.py
from unittest import mock, TestCase
from pack.abc import Abc
class TestAbc(TestCase):
#mock.patch('pack.def.Def')
def test_f(self, mock_def):
responses = ['response1', 'response2', 'response3']
mock_def.return_value.response.return_value = responses
assert responses == Abc().f()
I assumed the mock def has been patched, but I'm doing something wrong, does someone know I'm doing wrong?
You must mock the object your are working. You are using the Def that belongs to pack.def package in abc module. When you write test for Abc class, and want to mock Def calls, you must mock the Def that is imported in abc, not from original module.
Use #mock.patch('pack.abc.Def') instead of #mock.patch('pack.def.Def').
I have this code that I want to test:
log = logging.getLogger(__name__)
class A(object):
def __init__(self):
log.debug('Init')
but I cannot figure out how to assert that log.debug was called with 'Init'
I tried patching logger but inspecting it I only found a getLogger mock.
I'm sure its simple, but I just cant figure it!
Thanks in advance for any and all help!
You can use patch.object() on the actual logging object. that lets you verify that you're using the correct logger too:
logger = logging.getLogger('path.to.module.under.test')
with mock.patch.object(logger, 'debug') as mock_debug:
run_code_under_test()
mock_debug.assert_called_once_with('Init')
Alternatively, if you're using Pytest, then it already has a fixture that captures logs for you:
def test_bar(caplog):
with caplog.at_level(logging.DEBUG):
run_code_under_test()
assert "Init" in caplog.text
# or, if you really need to check the log-level
assert caplog.records[-1].message == "Init"
assert caplog.records[-1].levelname == "DEBUG"
More info in the pytest docs on logging
Assuming log is a global variable in a module mymod, you want to mock the actual instance that getLogger returned, which is what invokes debug. Then, you can check if log.debug was called with the correct argument.
with mock.patch('mymod.log') as log_mock:
# test code
log_mock.debug.assert_called_with('Init')
I am late for this question but another of way to achieve it is:
#patch('package_name.module_name.log')
def test_log_in_A(self, mocked_log):
a = A()
mocked_log.debug.assert_called_once_with('Init')
This also works:
from unittest.mock import patch
class Test(TestCase):
def test_logger(self):
with patch('logging.Logger.warning') as mocked_logger:
call_func()
mocked_logger.assert_called_once_with('log')
Here is a complete example
"""
Source to test
"""
import logging
logger = logging.getLogger("abc")
def my_fonction():
logger.warning("Oops")
"""
Testing part
"""
import unittest
from unittest.mock import patch, MagicMock
abc_logger = logging.getLogger("abc")
class TestApp(unittest.TestCase):
#patch.object(abc_logger, "warning", MagicMock())
def test_my_fonction(self):
# When
my_fonction()
# Then
abc_logger.warning.assert_called_once()
Here's an example class that simplifies what I have:
class.py
class MyClass(object):
#staticmethod
def getDictionary():
#some calculations, returns a dictionary
def checkConfiguration(self):
#some code
self.getDictionary()
#some other code
return value
And now I am making a unit test for checkConfiguration:
classTest.py
import class
import unittest
class TestMyClass(unittest.TestCase):
def setUp(self):
self.classTest = class.MyClass()
def test_CheckConfiguration(self):
#What to put here?
The original CheckConfiguration calls getDictionary. Is there a way to tell the test_CheckConfiguration(self) that if getDictionary is called, it should automatically return a dictionary I can type in?
Something like:
def test_CheckConfiguration(self):
if method getDictionary is called:
return {'a':123, 'b':22}
checkValue = self.classTest.checkConfiguration()
I know this is possible in Java, though I don't have enough experience in that nor this.
Thank you.
I think you need a mocking framework. I suggest PyMock.
Here's how you could use it:
classTest.py
import class
import pymock
import unittest
class TestMyClass(pymock.PyMockTestCase):
def setUp(self):
self.classTest = class.MyClass()
def test_CheckConfiguration(self):
self.override(self.classTest, 'getDictionary')
pymock.expectAndReturn(self.classTest.getDictionary(), {'a':123, 'b':22})
self.replay()
checkValue = self.classTest.checkConfiguration()
self.verify()
https://groups.google.com/forum/?fromgroups#!topic/comp.lang.python/WBhc1xAc8Hw suggests subclassing your class under test and overriding __getattribute__ to record each call in whatever manner you need. Not sure what else would work...