python patch. get Mock rather than MagicMock (with autospec) - python

How I can get Mock object as patch result rather than MagicMock in this short sample?
from unittest.mock import patch, Mock
class X:
x=1
with patch.object(X, 'x', autospec=True) as my_mock:
print(type(my_mock)) # NonCallableMagicMock, but need just a Mock/NonCallableMock

Related

Python Unit Test Patch Function - Avoid passing mocked function to test function

I am trying to mock a python function similar to below. I am not doing anything with the mocked function except for the fact that it is used to return the mocked data in the called function. Is it possible for me to avoid passing in the variable (sum, in this case) to the test function?
# test_calculator.py
from unittest import TestCase
from unittest.mock import patch
class TestCalculator(TestCase):
#patch('calculator.Calculator.sum', return_value=9)
def test_sum(self, sum):
self.assertEqual(sum(2,3), 9)
unittest.mock.patch can also be used as a context manager, if simply avoiding sum in the parameters is desired
class TestCalculator(TestCase):
def test_sum(self):
with patch('calculator.Calculator.sum', return_value=9) as sum:
self.assertEqual(sum(2, 3), 9)

py.test patch on fixture

I use the following to mock constant values for a test with py.test:
#patch('ConstantsModule.ConstantsClass.DELAY_TIME', 10)
def test_PowerUp():
...
thing = Thing.Thing()
assert thing.a == 1
This mocks DELAY_TIME as used in both the test, and in Thing, which is what I expected.
I wanted to do this for all the tests in this file, so I tried
#patch('ConstantsModule.ConstantsClass.DELAY_TIME', 10)
#pytest.fixture(autouse=True)
def NoDelay():
pass
But that doesn't seem to have the same effect.
Here is a similar question: pytest-mock mocker in pytest fixture, but the mock seems done in a non-decorator way there.
I'd say patching via decorator is not the optimal approach here. I'd use the context manager:
import pytest
from unittest.mock import patch
#pytest.fixture(autouse=True)
def no_delay():
with patch('ConstantsModule.ConstantsClass.DELAY_TIME', 10):
yield
This way, patching is cleanly reverted on test teardown.
pytest provides builtin patching support via the monkeypatch fixture. So to patch the constant for all tests in the file you can create the following autouse fixture:
#pytest.fixture(autouse=True)
def no_delay(monkeypatch):
monkeypatch.setattr(ConstantsModule.ConstantsClass, 'DELAY_TIME', 10)
If you don't want to have the ConstantsModule imported in your tests you can use a string, see the full API reference.

Mocking a module imported inside of a function

Is it possible to mock a module that's imported inside of a function?
for instance
def my_func(input):
import something_else
something_else.do_something(input)
I have an import inside of the function because of a circular dependency. Based on my googling I think I am SOL, but was wondering if anyone knew of way to make this possible.
I just want to verify that do_something gets called.
You can use the same technique that's described in this answer. In short you can patch sys.modules dict. So your test can be:
from unittest.mock import patch, MagicMock
...
def test_call_do_something(self):
m = MagicMock()
with patch.dict("sys.modules", something_else=m):
input_mock = MagicMock()
my_func(input_mock)
m.do_something.assert_called_with(input_mock)
You can rewrite it by patch decorator, but m should be a static instance.

Mocking a function in another file and a class in a second other file

I'm noticing that the class methods are being mocked out properly, but the function is bypassing the mock and running the actual function.
from module1 import myClass
from module2 import my_function
import unittest
from mock import patch
class TestStuff(unittest.TestCase):
#patch('module2.my_function')
#patch('module1.myClass.my_method')
def test_my_function(self, mock_method, mock_function):
test_obj = myClass()
test_obj.my_method()
assert mock_method.called
my_function()
assert mock_function.called
if I print out my_function() and type(my_function) it will not show the mock, but the real function. Does it matter that I'm importing a class then mocking a method, but I'm importing the function directly?
I think I found the issue:
When I'm testing a function, and there's something I want to mock, I should not import it. Importing it causes it to get used, even if I've put the patch decorator.
I think this was general confusion about how mocking/testing works. What I wanted to do was to test a function without actually querying the database. Instead of mocking out the whole function, I could take the line that actually hits the db - query.all() - and make it it's own function, then mock that out.
from module1 import myClass
from module2 import my_function
import unittest
from mock import patch
class TestStuff(unittest.TestCase):
#patch('module2.db_query')
#patch('module1.myClass.my_method')
def test_my_function(self, mock_method, mock_db_query):
test_obj = myClass()
test_obj.my_method()
assert mock_method.called
my_function() # my_function calls db_query(), now mocked out
assert mock_db_query.called
If I had wanted to actually mock out the all of my_function, I could have just not imported it. At least that's how I'm understanding this at the moment.
I ran into a similar issue. Turns out I needed to give it the FULL path to my_function:
#patch('home.myuser.myprojects.mymodule.myfunc')

implement decorator who will be substitute one class with another implementation

What I need is something like that:
def method():
my_var = module.Class1() #actually calling Class1 constructor
...
I need to implement decorator who will be change once class definition with another, like that:
#substitute(module.class1 = new_module.class2)
def method():
my_var = module.Class1() #actually calling new_module.class2 constructor
...
Could you please give me some hints how to do that.
What you are trying to do is called mocking. Use the mock library to do this; the library is part of Python 3.4 and up as unittest.mock.
With mock you can patch the original function while testing only:
try:
from unittest.mock import patch
except ImportError:
# Python < 3.4
from mock import patch
with patch('module.class1') as class1_mock:
mocked_instance = class1_mock.return_value
mocked_instance.method_to_be_called.return_value = 'Test return value'
method()
mocked_instance.method_to_be_called.assert_called_with('Foo', 'bar')
The above mocks out class1 for the duration of the with block, undoing the patch afterwards. The patch replaces module.class1 with a Mock object, which you also have access to as class1_mock. The above example sets up method_to_be_called to return a rigged test return value, and after the test the call signature is verified.

Categories