Patch a method outside python class - python

I am interested in patching a method which is called by another method in one file. Example - original.py file contains -
def A():
a = 10
b = 5
return a*b;
def B():
c = A()
return c* 10
I want to write unit test for this file , say call it test.py
import mock
import unittest
class TestOriginal(unitest.TestCase):
def test_Original_method(self):
with patch(''):
How can I use patch and mock modules to test original.py. I want A() to always return MagicMock() object instead of an integer.

You simply patch out the A global in the module under test. I'd use the #patch decorator syntax here:
import mock
import unittest
import module_under_test
class TestOriginal(unitest.TestCase):
#patch('module_under_test.A')
def test_Original_method(self, mocked_A):
mocked_A.return_value = 42
result = module_under_test.B()
mocked_A.assert_called_with()
self.assertEqual(result, 420)
This passes in the MagicMock mock object for A() as an extra argument to the test method.
Note that we explicitly named the module here. You could also use patch.object(), just naming the attribute on the module (which are your module globals):
class TestOriginal(unitest.TestCase):
#patch.object(module_under_test, 'A')
def test_Original_method(self, mocked_A):
mocked_A.return_value = 42
result = module_under_test.B()
mocked_A.assert_called_with()
self.assertEqual(result, 420)
You can still use a with statement too, of course:
class TestOriginal(unitest.TestCase):
def test_Original_method(self):
with patch('module_under_test.A') as mocked_A:
mocked_A.return_value = 42
result = module_under_test.B()
mocked_A.assert_called_with()
self.assertEqual(result, 420)

Related

Python unit test #mock.patch set mock property

Is there a way to have class patches with mocked properties set in once place? Say I have the following class I want to test.
class ExampleClass
def __init__(self, specific_args):
# Do something with specific args
self.specific_args = specific_args
self.sub_component = SubComponent(...)
def example_function_double_value(self) -> float:
return SomeFunction(self.specific_args, self.sub_component.value)
and it has the following unit test where I patch out SubComponent and set SubComponent.value to return 3.
import unittest
from unittest import mock
def set_patch(patch: mock.Mock):
patch_return_value = mock.Mock()
patch_return_value.value = 3
patch.return_value = patch_return_value
#mock.patch('SubComponent_Path.SubComponent')
class ExampleUnitTest(unittest.TestCase)
def test_case1(self, patch):
set_patch(patch)
specific_args1 = # Generate specific arguments for this test case
test_class = ExampleClass(specfic_args1)
# Some assertion where I expect `subcomponent.value to be 3`
def test_case2(self, patch):
set_patch(patch)
specific_args2 = # Generate specific arguments for this test case
test_class = ExampleClass(specfic_args2)
# Some other assertion where I expect `subcomponent.value to be 3`
Is there a more elegant way to do this without needing to call that helper function at the start of each test?
Setting return_value attribute of the mock is an efficient way to do it so we don't need to call the helper function.
import unittest
from unittest import mock
#mock.patch('SubComponent_Path.SubComponent')
class ExampleUnitTest(unittest.TestCase)
def setUp(self):
self.example_class = ExampleClass()
self.mocked_sub_component = self.example_class.sub_component
self.mocked_sub_component.value.return_value = 3
def test_case1(self, patch):
self.assertEqual(self.example_class.example_function_double_value, 6)
def test_case2(self, patch):
# Some other test case where I expect `subcomponent.value to be 3`

How to Mock a class and its methods which are used by another .py

I am trying to mock a class and its method that is used by another class.
My file structure is:
[1] my_animal.py contains Myclass and method: do_bite()
my_animal.py
class Myclass():
def do_bite(self):
return 1
[2] my_module.py contains jobMain("") which is using the method from my_animal.py
my_module.py
import sys
from my_animal import Myclass
def jobMain(directoryPath):
result = Myclass()
if result.do_bite() is None:
sys.exit(1) # stop here
[3] my_test.py contains the unittest to test jobMain in my_module.py
my_test.py
from my_animal import Myclass
# Try to mock Myclass
#pytest.fixture
def mock_Myclass(monkeypatch):
""" Mock myclass """
monkeypatch.setattr(my_module, "Myclass", MagicMock())
# I tried below code to mock dobite() method, but it was unsuccessfully
# Mock Myclass.dobite to None"""
#pytest.fixture
def mock_dobite(monkeypatch):
def mock_return(*args, **kwargs):
with patch('my_animal',dobite) as p:
instance = p.return_value
instance.dobite = Mock(return_value = None)
monkeypatch.setattr(my_module.Myclass, "do_bite", mock_return )
# My unittest to test dobite() method
def test_dobite(mock_Myclass, mock_dobite):
with pytest.raises(SystemExit) as s_exit:
jobMain("")
assert s_exit.type == SystemExit
assert s_exit.value.code == 1
My question is: How could I mock the return value of the method do_bite() to None or any other expected value?
Your fixture is overly complicated, here is what you can use:
import pytest
from unittest import mock
#pytest.fixture
def mock_dobite():
with mock.patch('my_module.Myclass') as mocked_animal:
mocked_animal.return_value.do_bite.return_value = None
yield
You patch the class as it is imported (see where to patch). Because Myclass is imported like this:
from my_animal import Myclass
you have a local reference to the module, which you have to patch.
mocked_animal is the mocked class. To get the instance of the class, you have to use mocked_animal.return_value. By adding do_bite.return_value, you now can set the return value of the method do_bite.
Now your test will work like this (note that you need only one fixture parameter):
def test_dobite(mock_dobite):
with pytest.raises(SystemExit) as s_exit:
jobMain("")
assert s_exit.type == SystemExit
assert s_exit.value.code == 1

How to mock init of helper class

I am having trouble with checking if an object is being constructed with the proper params from another instance of an object. In the below example, I am trying to create an instance of B within an instance of A. I want to check the parameter being used in the constructor of B inside of the A instance. When I run the test below, I get:
AssertionError: assert None
[CPython36:setup:stdout] E + where None = <bound method NonCallableMock.assert_called_with of <MagicMock name='B' id='139968329210736'>>(4)
[CPython36:setup:stdout] E + where <bound method NonCallableMock.assert_called_with of <MagicMock name='B' id='139968329210736'>> = <MagicMock name='B' id='139968329210736'>.assert_called_with
I am not quite sure what I am doing wrong here and have looked at other stack overflow posts, but have not been able to solve my issue.
b.py:
class B(object):
def __init__(self, x):
self.x = x
def square(self):
return x * x
a.py:
from b import B
class A(object):
def foo(self):
b = B(4)
b.square()
test_a.py:
import unittest
from unittest.mock import patch
from a import A
class TestA(unittest.TestCase):
#patch('a.B')
def test_foo(self, mock_b):
self.a = A()
self.a.foo()
assert mock_b.assert_called_with(4)
The method assert_called_with returns None, so what your are doing is like doing
assert None
And that's basically the error message you are getting.
You can just use
mock_b.assert_called_with(4)
Which has an assert internally and pytest will display it correctly in case of failure. Try to check it by changing the argument value.
Alternatively, if you prefer to write the assert yourself, you can do something like this:
from unittest.mock import call
assert mock_b.call_args_list == [call(4)]
Or just the last call:
from unittest.mock import call
assert mock_b.call_args == call(4)

Mocking Methods within Classes

I've read a lot of information online about mocking entire classes. However, I have a class with multiple methods; for example:
class A():
def methoda(param1, param2):
do things
return thing
def methodb(param3):
do things (including something calling methoda)
How can I mock out methoda in a testing file to return a desired value so that I can test methodb? I don't want to mock out the entire class.
What I've tried doing:
from mock import patch, mock, MagicMock
from sourceA.models import ClassName
from django.test import TestCase
class ClassTest(TestCase):
#patch('sourceA.models.ClassName.methodA')
def test_method(self, mock_method_return):
mock_method_return.return_value = 10
instance = ClassName()
instance.methodB #METHOD B CALLS METHOD A; I want method A to return 10
print "OUTPUT", instance.FIELDA #Debug Tool - Field A is modified by Method B, based on the return value of method A
assert instance.FIELDA == 10
I have also tried this:
class ClassTest(TestCase):
#patch('sourceA.models.ClassName.methodA', return_value=10)
def test_method(self, mock_method_return):
instance = Mock(spec=ClassName())
instance.methodB #METHOD B CALLS METHOD A; I want method A to return 10
------ OR instance methodB = MagicMock(return_value=10) and then instance.MethodB
print "OUTPUT", instance.FIELDA #Debug Tool - Field A is modified by Method B, based on the return value of method A
self.assertEqual(instance.FIELDA, 10)
I'm not sure what else I should try/what I am doing wrong.

Using Python mock to spy on calls to an existing object

I'm using the Python mock module for tests. I would like to replace an active object with a mock, and automatically have all calls made to the mock object forwarded to the original object. I think this is called a "Spy" in standard testing terminology. At the moment I'm doing inside a test:
# Insert a mock replacement
orig_active_attr = server.active_attr
server.active_attr = mock.Mock()
# Set up side effects to 'proxy' to the original object
server.active_attr.meth1.side_effect = orig_active_attr.meth1
server.active_attr.meth2.side_effect = orig_active_attr.meth2
# Call the method being tested
server.method_being_tested()
# Assert stuff on the mock.
server.active_attr.meth2.assert_called_once()
It would be nice if all method calls on the mock could be forwarded to the live object automatically without the boilerplate.
I seem to have stumbled across the solution:
import mock
class A(object):
def meth(self, a):
return a
a = A()
ma = mock.Mock(wraps=a)
Seems to work okay for functions, methods and properties, but not for class or instance attributes.
See the documentation.
You can use patch.object(wraps=obj_instance) as suggested in Spying on instance methods with Python's mock module.
For example:
from mock import patch
class Foo(object):
def bar(self, x, y):
return x + y + 1
def test_bar():
foo = Foo()
with patch.object(foo, 'bar', wraps=foo.bar) as wrapped_foo:
foo.bar(1, 2)
wrapped_foo.assert_called_with(1, 2)
Here's how to mock only datetime.date.today(), forwarding the rest of datetime calls to the datetime module:
from unittest import mock, TestCase
import foo_module
class FooTest(TestCase):
#mock.patch(f'{foo_module.__name__}.datetime', wraps=foo_module.datetime)
def test_something(self, mock_datetime):
# mock only datetime.date.today()
mock_datetime.date.today.return_value = datetime.date(2019, 3, 15)
# other calls to datetime functions will be forwarded to original datetime
foo_module imports datetime and uses many other datetime functions besides date.today.
You can use a simple function to iterate through all the method and configure your mock
def spy_mock(instance):
members = inspect.getmembers(instance, inspect.ismethod)
attrs = {'%s.side_effect' % k:v for k,v in members}
return mock.Mock(**attrs)
Usage would be
import inspect
from unittest import mock
class ActiveAttr:
def meth2(self):
print("Meth2 called")
class Server:
def __init__(self):
self.active_attr = ActiveAttr()
def method_being_tested(self):
self.active_attr.meth2()
def spy_mock(instance):
members = inspect.getmembers(instance, inspect.ismethod)
attrs = {'%s.side_effect' % k:v for k,v in members}
return mock.Mock(**attrs)
server = Server()
server.active_attr = spy_mock(server.active_attr)
server.method_being_tested()
server.active_attr.meth2.assert_called_once()
Extending upon the pattern from Wes McKinney (via Wilfred Hughes Answer), here is how to spy on a method/member of an object, where object is imported into module under test.
Note this solution is Python 2.x compliant!
module under test:
import object
def function_in_module_under_test():
object.method_from_imported_object()
testing spied assertion on method_from_imported_object:
from unittest import mock
import module_under_test
def test_method(self):
with mock.patch.object(
module_under_test.object,
"method_from_imported_object",
module_under_test.object.method_from_imported_object,
) as spy_method_from_imported_object:
# Demonstrate that subsequent spy asserts here, can be trusted
spy_method_from_imported_object.assert_not_called()
# now Test
module_under_test.function_in_module_under_test()
spy_method_from_imported_object.assert_called_once()
If you use pytest, the pytest-mock package has a convenient spy object.
class Foo(object):
def bar(self, v):
return v * 2
def test_spy_method(mocker):
foo = Foo()
spy = mocker.spy(foo, 'bar')
assert foo.bar(21) == 42
spy.assert_called_once_with(21)
assert spy.spy_return == 42

Categories