How to mock a method of an imported instance - python

I am writing unit test for some python modules. However, I cannot work out a way to mock a method of an imported instance. Below is the python modules that I want to test.
--bar.py--
class A():
#classmethod
def method_1(self):
...
a = A()
--foo.py--
from bar import a
class B():
#classmethod
def b(cls):
if a.method_1():
return True
else:
return False
--test_foo.py--
from foo import B
class TestB(TestCase):
#patch('foo.a.method_1')
def test_b(self, mock_method_1):
mock_method_1.return_value = True
test_b = B.b()
...
This does not work. My test case is still calling original method_1 instead of the one I mocked.

Use the patch.object decorator instead. It patches an object's attributes instead of patching a global method.
If that doesn't work, try patching bar.a instead of foo.a, but I don't think that's your problem here.
Update
The question changed to a class method, so I think this will work:
--test_foo.py--
from foo import B
class TestB(TestCase):
#patch('bar.A.method_1')
def test_b(self, mock_method_1):
mock_method_1.return_value = True
test_b = B.b()
...

Related

Python, can't assert if method called from another class

I have the following code in Python:
class A():
def doSomething(self, bClass):
print(bClass.theThing)
class B():
def __init__(self, theThing):
self.theThing = theThing
def foo():
a = A()
b = B("that thing")
a.doSomething(b)
I have those classes and the function foo() stored in testing.py and I want to test that the A's method was called with:
import testing, unittest
from unittest.mock import patch
class TheTestClass(unittest.TestCase):
def test(self):
with patch('testing.A.doSomething') as do:
testing.foo()
do.assert_any_call()
But I always get 'doSomething() call not found'. I would be happier if I could understand why but at this point anything is welcome
After many hours I started figuring this out.
Like jwjhdev said assert_called_with() expects something and in my case a class but so does assert_any_call(). For some reason I was thinking assert_any_call() would just work but what I was thinking was assert_called() which just works without arguments. In the end I figured it out by adding a return b to the foo() function and:
def foo():
a = A()
b = B("that thing")
a.doSomething(b)
return b
class TheTestClass(unittest.TestCase):
def test(self):
with patch('testing.A.doSomething') as do:
b = testing.foo()
do.assert_any_call(b)

How does one use pytest monkeypatch to patch a class

I would like to use [pytest monkeypatch][1] to mock a class which is imported
into a separate module. Is this actually possible, and if so how does one do it? It seems like I have not seen an example for this exact situation. Suppose you have app with and imported class A in something.py
from something import A #Class is imported
class B :
def __init__(self) :
self.instance = A() #class instance is created
def f(self, value) :
return self.instance.g(value)
inside my test.py I want to mock A inside B
from something import B
#this is where I would mock A such that
def mock_A :
def g(self, value) :
return 2*value
#Then I would call B
c = B()
print(c.g(2)) #would be 4
I see how monkeypatch can be used to patch instances of classes, but how is it done for classes that have not yet been instantiated? Is it possible? Thanks!
[1]: https://docs.pytest.org/en/latest/monkeypatch.html
tested this, works for me:
def test_thing(monkeypatch):
def patched_g(self, value):
return value * 2
monkeypatch.setattr(A, 'g', patched_g)
b = B()
assert b.f(2) == 4

Python Mock - check if method was called from another class?

How can I check if method is called inside another method, when those methods are from different classes?
If they are from same class, I can do this:
from unittest import mock
class A():
def method_a(self):
pass
def method_b(self):
self.method_a()
a = A()
a.method_a = mock.MagicMock()
a.method_b()
a.method_a.assert_called_once_with()
But if method_a would be from different class, then it would raise AssertionError that it was not called.
How could I do same check if I would have these classes instead (and I want to check if method_b calls method_a)?:
class A():
def method_a(self):
pass
class B():
def method_b(self):
A().method_a()
You have to simply stub A within the same context as B, and validate against the way it would have been called. Example:
>>> class B():
... def method_b(self):
... A().method_a()
...
>>> A = mock.MagicMock()
>>> A().method_a.called
False
>>> b = B()
>>> b.method_b()
>>> A().method_a.called
True
>>>

How to redefine python3 MagicMock magic method?

I need to redefine MagicMock's magic method in the child class and then use child class for testing, so I've tried:
from unittest.mock import MagicMock
class MockForTest(MagicMock):
def __lt__(self):
return self
t1 = MockForTest()
print(t1.__lt__()) # prints NotImplemented
But why NotImplemented? I know I can do it:
class A():
def __lt__(self):
return NotImplemented
class B(A):
def __lt__(self):
return self
b = B()
print(b.__lt__()) # prints <__main__.B object at 0x000001D6EE77B2B0>
So, I can't redefine MagicMock's magic methods?
You can use instead
t1.__lt__.return_value = t1
From what I can understand from https://github.com/python/cpython/blob/4002d5dbf4c058bbf2462f9f5dea057956d1caff/Lib/unittest/mock.py#L1834 MagicMixin remove all other magic methods.

Using python's mock patch.object to change the return value of a method called within another method

Is it possible to mock a return value of a function called within another function I am trying to test? I would like the mocked method (which will be called in many methods I'm testing) to returned my specified variables each time it is called. For example:
class Foo:
def method_1():
results = uses_some_other_method()
def method_n():
results = uses_some_other_method()
In the unit test, I would like to use mock to change the return value of uses_some_other_method() so that any time it is called in Foo, it will return what I defined in #patch.object(...)
There are two ways you can do this; with patch and with patch.object
Patch assumes that you are not directly importing the object but that it is being used by the object you are testing as in the following
#foo.py
def some_fn():
return 'some_fn'
class Foo(object):
def method_1(self):
return some_fn()
#bar.py
import foo
class Bar(object):
def method_2(self):
tmp = foo.Foo()
return tmp.method_1()
#test_case_1.py
import bar
from mock import patch
#patch('foo.some_fn')
def test_bar(mock_some_fn):
mock_some_fn.return_value = 'test-val-1'
tmp = bar.Bar()
assert tmp.method_2() == 'test-val-1'
mock_some_fn.return_value = 'test-val-2'
assert tmp.method_2() == 'test-val-2'
If you are directly importing the module to be tested, you can use patch.object as follows:
#test_case_2.py
import foo
from mock import patch
#patch.object(foo, 'some_fn')
def test_foo(test_some_fn):
test_some_fn.return_value = 'test-val-1'
tmp = foo.Foo()
assert tmp.method_1() == 'test-val-1'
test_some_fn.return_value = 'test-val-2'
assert tmp.method_1() == 'test-val-2'
In both cases some_fn will be 'un-mocked' after the test function is complete.
Edit:
In order to mock multiple functions, just add more decorators to the function and add arguments to take in the extra parameters
#patch.object(foo, 'some_fn')
#patch.object(foo, 'other_fn')
def test_foo(test_other_fn, test_some_fn):
...
Note that the closer the decorator is to the function definition, the earlier it is in the parameter list.
This can be done with something like this:
# foo.py
class Foo:
def method_1():
results = uses_some_other_method()
# testing.py
from mock import patch
#patch('Foo.uses_some_other_method', return_value="specific_value"):
def test_some_other_method(mock_some_other_method):
foo = Foo()
the_value = foo.method_1()
assert the_value == "specific_value"
Here's a source that you can read: Patching in the wrong place
Let me clarify what you're talking about: you want to test Foo in a testcase, which calls external method uses_some_other_method. Instead of calling the actual method, you want to mock the return value.
class Foo:
def method_1():
results = uses_some_other_method()
def method_n():
results = uses_some_other_method()
Suppose the above code is in foo.py and uses_some_other_method is defined in module bar.py. Here is the unittest:
import unittest
import mock
from foo import Foo
class TestFoo(unittest.TestCase):
def setup(self):
self.foo = Foo()
#mock.patch('foo.uses_some_other_method')
def test_method_1(self, mock_method):
mock_method.return_value = 3
self.foo.method_1(*args, **kwargs)
mock_method.assert_called_with(*args, **kwargs)
If you want to change the return value every time you passed in different arguments, mock provides side_effect.
To add to Silfheed's answer, which was useful, I needed to patch multiple methods of the object in question. I found it more elegant to do it this way:
Given the following function to test, located in module.a_function.to_test.py:
from some_other.module import SomeOtherClass
def add_results():
my_object = SomeOtherClass('some_contextual_parameters')
result_a = my_object.method_a()
result_b = my_object.method_b()
return result_a + result_b
To test this function (or class method, it doesn't matter), one can patch multiple methods of the class SomeOtherClass by using patch.object() in combination with sys.modules:
#patch.object(sys.modules['module.a_function.to_test'], 'SomeOtherClass')
def test__should_add_results(self, mocked_other_class):
mocked_other_class().method_a.return_value = 4
mocked_other_class().method_b.return_value = 7
self.assertEqual(add_results(), 11)
This works no matter the number of methods of SomeOtherClass you need to patch, with independent results.
Also, using the same patching method, an actual instance of SomeOtherClass can be returned if need be:
#patch.object(sys.modules['module.a_function.to_test'], 'SomeOtherClass')
def test__should_add_results(self, mocked_other_class):
other_class_instance = SomeOtherClass('some_controlled_parameters')
mocked_other_class.return_value = other_class_instance
...

Categories

Resources