So I've this code that mocks two times, the first time by mocking imports with:
sys.modules['random'] = MagicMock()
The second time happens inside the unittest of a function that used that import, for example a function that used random
The tests. py is:
import sys
import unittest
from unittest import mock
from unittest.mock import MagicMock
import foo
sys.modules['random'] = MagicMock()
class test_foo(unittest.TestCase):
def test_method(self):
with mock.patch('random.choice', return_value = 2):
object = foo.FooClass(3)
self.assertEqual(2, object.method(), 'Should be 2')
def test_staticmethod(self):
with mock.patch('random.choice', return_value = 2):
object = foo.FooClass(3)
self.assertEqual(2, object.method(), 'should be 2')
The original file Foo.py is:
import random
class FooClass:
def __init__(self,arg):
self.arg = arg
def method(self):
print(random.choice)
return random.choice([1,2,3])
#staticmethod
def staticmethod():
print(random.choice)
random.choice([1,2,3])
The two mocks contrarrest each other, and the mocking of random doesn't happen.
When it prints random it actually prints:
<<bound method Random.choice of <random.Random object at 0x7fe688028018>>
I want that to print a MagicMock.
Can someone help me understand what's happening? Why are they contrarresting each other?
You don't need to update the module source with sys.modules['random'] = MagicMock() without this line it works fine <MagicMock name='choice' id='...'>. patch already does all the work for the isolated temporary updating the method. See more explanation in the docs - Where to patch
I'm encountering a problem with unit testing in Python. Specifically, when I try to mock a function my code imports, variables assigned to the output of that function get assigned to a MagicMock object instead of the mock-function's return_value. I've been digging through the docs for python's unittest library, but am not having any luck.
The following is the code I want to test:
from production_class import function_A, function_B, function_M
class MyClass:
def do_something(self):
variable = functionB()
if variable:
do_other_stuff()
else:
do_something_else
this is what I've tried:
#mock.patch(path.to.MyClass.functionB)
#mock.patch(<other dependencies in MyClass>)
def test_do_something(self, functionB_mock):
functionB_mock.return_value = None # or False, or 'foo' or whatever.
myClass = MyClass()
myClass.do_something()
self.assertTrue(else_block_was_executed)
The issue I have is that when the test gets to variable = functionB in MyClass, the variable doesn't get set to my return value; it gets set to a MagicMock object (and so the if-statement always evaluates to True). How do I mock an imported function such that when executed, variables actually get set to the return value and not the MagicMock object itself?
We'd have to see what import path you're actually using with path.to.MyClass.functionB. When mocking objects, you don't necessarily use the path directly to where the object is located, but the one that the intepreter sees when recursively importing modules.
For example, if your test imports MyClass from myclass.py, and that file imports functionB from production_class.py, the mock path would be myclass.functionB, instead of production_class.functionB.
Then there's the issue that you need additional mocks of MyClass.do_other_stuff and MyClass.do_something_else in to check whether MyClass called the correct downstream method, based on the return value of functionB.
Here's a working example that tests both possible return values of functionB, and whether they call the correct downstream method:
myclass.py
from production_class import functionA, functionB, functionM
class MyClass:
def do_something(self):
variable = functionB()
if variable:
self.do_other_stuff()
else:
self.do_something_else()
def do_other_stuff(self):
pass
def do_something_else(self):
pass
production_class.py
import random
def functionA():
pass
def functionB():
return random.choice([True, False])
def functionM():
pass
test_myclass.py
import unittest
from unittest.mock import patch
from myclass import MyClass
class MyTest(unittest.TestCase):
#patch('myclass.functionB')
#patch('myclass.MyClass.do_something_else')
def test_do_something_calls_do_something_else(self, do_something_else_mock, functionB_mock):
functionB_mock.return_value = False
instance = MyClass()
instance.do_something()
do_something_else_mock.assert_called()
#patch('myclass.functionB')
#patch('myclass.MyClass.do_other_stuff')
def test_do_something_calls_do_other_stuff(self, do_other_stuff_mock, functionB_mock):
functionB_mock.return_value = True
instance = MyClass()
instance.do_something()
do_other_stuff_mock.assert_called()
if __name__ == '__main__':
unittest.main()
calling python test_myclass.py results in:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
What I wound up doing was changing the import statements in MyClass to import the object instead of the individual methods. I was then able to mock the object without any trouble.
More explicitly I changed MyClass to look like this:
import production_class as production_class
class MyClass:
def do_something(self):
variable = production_class.functionB()
if variable:
do_other_stuff()
else:
do_something_else
and changed my test to
#mock.patch(path.to.MyClass.production_class)
def test_do_something(self, prod_class_mock):
prod_class_mock.functionB.return_value = None
myClass = MyClass()
myClass.do_something()
self.assertTrue(else_block_was_executed)
New to mock and patch in python. I have a class which has a method update
class myclass(object):
def update(self, name, passwd):
self.update_in(name,passwd)
def update_in(self, name, passwd):
self.name = name
self.passwd = passwd
Now in another class I have to test the update method and ascertain that the update method calls in update_in method. How do I achieve this ?
By patch from unittest.mock module you can patch methods, functions, object or attribute of your production code. Now I assume myclass in mymodule and I will show you some simple way of how to do your test.
from unittest.mock import patch
from mymodule import myclass
m = myclass()
with patch("mymodule.myclass.update_in", autospec=True) as mock_update_in:
m.update('me', 'mypassword')
mock_update_in.assert_called_with('me', 'mypassword')
#patch("mymodule.myclass.update_in", autospec=True)
def my_test(mock_update_in):
m = myclass()
m.update('me', 'mypassword')
mock_update_in.assert_called_with('me', 'mypassword')
my_test()
Now instead of patch you can use patch.object(myclass, "update_in", autospec=True) and patch the reference of myclass in the module of your tests. My feel is to use patch.object just when you cannot do otherwise: you must be sure that you are patching the code that will be called by your test and not something else. For instance you have mymodule_b the use from mymodule import myclass and now you test a method in mymodule_b like:
from mymodule import myclass
def get_registered(username, password):
m = myclass()
m.update(username, password)
return m
Now the reference of myclass used by get_registered() is not the one in your test module. Next test will fail
from mymodule import myclass
from mymodule_b import get_registered
with patch.object(myclass, "update_in", autospec=True) as mock_update_in:
m = get_registered('me', 'mypassword')
assert m is not None
mock_update_in.assert_called_with('me', 'mypassword')
Is a good practice take a look to Where to patch session before to start to ride patch functions.
Just a note about use autospec=True: autospec is a real powerful option of patch functions family, your patched object will take the signature and the attributes from the original reference and prevent some silly errors in your test. To understand the value of autospec take a look to the next example:
m = myclass()
with patch("mymodule.myclass.update_in") as mock_update_in:
m.update('me', 'mypassword')
mock_update_in.assert_call_with('you', 'yourpassword')
The previous test pass even if you check by the wrong arguments just because mock_update_in is a standard MagicMock() return a MagicMock object for every attribute you ask or every method you call without raise any exception: in that scenario mock_update_in.assert_call_with('you', 'yourpassword') will return a MagicMock().
You should use mock.patch to replace the method with a mock, and then you can assert various things about the mock after calling your update method.
patcher = mock.patch.object(myclass, 'update_in')
patched = patcher.start()
m=myclass()
m.update('foo', 'bar')
assert patched.call_count == 1
patched.assert_called_with('foo', 'bar')
class HelloWorld(object):
def say_it(self):
return 'Hello I am Hello World'
def i_call_hello_world(hw_obj):
print 'here... check type: %s' %type(HelloWorld)
if isinstance(hw_obj, HelloWorld):
print hw_obj.say_it()
from mock import patch, MagicMock
import unittest
class TestInstance(unittest.TestCase):
#patch('__main__.HelloWorld', spec=HelloWorld)
def test_mock(self,MK):
print type(MK)
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print v
if __name__ == '__main__':
c = HelloWorld()
i_call_hello_world(c)
print isinstance(c, HelloWorld)
unittest.main()
Here is the traceback
here... check type: <type 'type'>
Hello I am Hello World
True
<class 'mock.MagicMock'>
here... check type: <class 'mock.MagicMock'>
E
======================================================================
ERROR: test_mock (__main__.TestInstance)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/mock.py", line 1224, in patched
return func(*args, **keywargs)
File "t.py", line 18, in test_mock
v = i_call_hello_world(MK)
File "t.py", line 7, in i_call_hello_world
if isinstance(hw_obj, HelloWorld):
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types
----------------------------------------------------------------------
Ran 1 test in 0.002s
Q1. Why is this error thrown? They are <class type='MagicMock>
Q2. How do I pause the mocking so that the first line will pass if the error is fixed?
From the docs:
Normally the __class__ attribute of an object will return its type. For a mock object with a spec, __class__ returns the spec class instead. This allows mock objects to pass isinstance() tests for the object they are replacing / masquerading as:
mock = Mock(spec=3)
isinstance(mock, int)
True
IMHO this is a good question and saying "don't use isinstance, use duck typing instead" is a bad answer. Duck typing is great, but not a silver bullet. Sometimes isinstance is necessary, even if it is not pythonic. For instance, if you work with some library or legacy code that isn't pythonic you must play with isinstance. It is just the real world and mock was designed to fit this kind of work.
In the code the big mistake is when you write:
#patch('__main__.HelloWorld', spec=HelloWorld)
def test_mock(self,MK):
From patch documentation we read (emphasize is mine):
Inside the body of the function or with statement, the target is patched with a new object.
That means when you patch the HelloWorld class object the reference to HelloWorld will be replaced by a MagicMock object for the context of the test_mock() function.
Then, when i_call_hello_world() is executed in if isinstance(hw_obj, HelloWorld): HelloWorld is a MagicMock() object and not a class (as the error suggests).
That behavior is because as a side effect of patching a class reference the 2nd argument of isinstance(hw_obj, HelloWorld) becomes an object (a MagicMock instance). This is neither a class or a type. A simple experiment to understand this behavior is to modify i_call_hello_world() as follows:
HelloWorld_cache = HelloWorld
def i_call_hello_world(hw_obj):
print 'here... check type: %s' %type(HelloWorld_cache)
if isinstance(hw_obj, HelloWorld_cache):
print hw_obj.say_it()
The error will disappear because the original reference to HelloWorld class is saved in HelloWorld_cache when you load the module. When the patch is applied it will change just HelloWorld and not HelloWorld_cache.
Unfortunately, the previous experiment doesn't give us any way to play with cases like yours because you cannot change the library or legacy code to introduce a trick like this. Moreover, these are that kind of tricks that we would like to never see in our code.
The good news is that you can do something ,but you cannot just patch the HelloWord reference in the module where you have isinstace(o,HelloWord) code to test. The best way depends on the real case that you must solve. In your example you can just create a Mock to use as HelloWorld object, use spec argument to dress it as HelloWorld instance and pass the isinstance test. This is exactly one of the aims for which spec is designed. Your test would be written like this:
def test_mock(self):
MK = MagicMock(spec=HelloWorld) #The hw_obj passed to i_call_hello_world
print type(MK)
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print v
And the output of just unittest part is
<class 'mock.MagicMock'>
here... check type: <type 'type'>
I am fake
None
Michele d'Amico provides the correct answer in my view and I strongly recommend reading it. But it took me a while a grok and, as I'm sure I'll be coming back to this question in the future, I thought a minimal code example would help clarify the solution and provide a quick reference:
from mock import patch, mock
class Foo(object): pass
# Cache the Foo class so it will be available for isinstance assert.
FooCache = Foo
with patch('__main__.Foo', spec=Foo):
foo = Foo()
assert isinstance(foo, FooCache)
assert isinstance(foo, mock.mock.NonCallableMagicMock)
# This will cause error from question:
# TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types
assert isinstance(foo, Foo)
You can do it by being inherited from the MagicMock class and overriding the __subclasscheck__ method:
class BaseMagicMock(MagicMock):
def __subclasscheck__(self, subclass):
# I couldn't find another way to get the IDs
self_id = re.search("id='(.+?)'", self.__repr__()).group(1)
subclass_id = re.search("id='(.+?)'", subclass.__repr__()).group(1)
return self_id == subclass_id
# def __instancecheck__(self, instance) for `isinstance`
And then you can use this class with the #patch decorator:
class FooBarTestCase(TestCase):
...
#patch('app.services.ClassB', new_callable=BaseMagicMock)
#patch('app.services.ClassA', new_callable=BaseMagicMock)
def test_mock_for_issubclass_support(self, ClassAMock, ClassBMock):
check_for_subclasses(ClassAMock)
That's it!
Remarks:
You MUST mock all classes which are compared using issubclass.
Example:
def check_for_subclasses(class_1):
if issubclass(class_1, ClassA): # it's mocked above using BaseMagicMock
print("This is Class A")
if issubclass(class_1, ClassB): # it's mocked above using BaseMagicMock
print("This is Class B")
if issubclass(class_1, ClassC): # it's not mocked with #patch
print("This is Class C")
issubclass(class_1, ClassC) will cause an error
{TypeError}issubclass() arg 1 must be a class because ClassC contains a default __issubclass__ method. And then we should handle the test like this:
class FooBarTestCase(TestCase):
...
#patch('app.services.ClassC', new_callable=BaseMagicMock)
#patch('app.services.ClassB', new_callable=BaseMagicMock)
#patch('app.services.ClassA', new_callable=BaseMagicMock)
def test_mock_for_issubclass_support(self, ClassAMock, ClassBMock):
check_for_subclasses(ClassAMock)
Just patch the isinstance method with:
#patch('__main__.isinstance', return_value=True)
So you will get expected behavior and coverage, you can always assert that mock method was called, see test case sample below:
class HelloWorld(object):
def say_it(self):
return 'Hello I am Hello World'
def i_call_hello_world(hw_obj):
print('here... check type: %s' %type(HelloWorld))
if isinstance(hw_obj, HelloWorld):
print(hw_obj.say_it())
from unittest.mock import patch, MagicMock
import unittest
class TestInstance(unittest.TestCase):
#patch('__main__.isinstance', return_value=True)
def test_mock(self,MK):
print(type(MK))
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print(v)
self.assertTrue(MK.say_it.called)
#patch('__main__.isinstance', return_value=False)
def test_not_call(self, MK):
print(type(MK))
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print(v)
self.assertFalse(MK.say_it.called)
I've been wrestling with this myself lately while writing some unit tests. One potential solution is to not actually try to mock out the entire HelloWorld class, but instead mock out the methods of the class that are called by the code you are testing. For example, something like this should work:
class HelloWorld(object):
def say_it(self):
return 'Hello I am Hello World'
def i_call_hello_world(hw_obj):
if isinstance(hw_obj, HelloWorld):
return hw_obj.say_it()
from mock import patch, MagicMock
import unittest
class TestInstance(unittest.TestCase):
#patch.object(HelloWorld, 'say_it')
def test_mock(self, mocked_say_it):
mocked_say_it.return_value = 'I am fake'
v = i_call_hello_world(HelloWorld())
self.assertEquals(v, 'I am fake')
I think it's safe to use freezegun. All the necessary preparations for correctly mocking the datetime module are made there. Also, the isinstance check does not fail for me.
It works like this:
#freeze_time("2019-05-15")
def test_that_requires_frozen_time(): ...
isinstance is a built-in function, and it is not a good idea to patch built-in functions as it is explained in this answer. In order to make isinstance return the value you want, and avoid this error:
TypeError: isinstance() arg 2 must be a type or tuple of types
You can patch isinstance in the module under test. I also encourage you to use patch as a context manager in a with statement as follows:
from mock import patch
def test_your_test(self):
# your test set up
with patch('your_module.isinstance', return_value=True): # or False
# logic that uses isinstance
Using patch as a context manager allows you to mock just in the specific function/method that you want to mock it instead of mocking it in the whole test.
I guess the possible solution can be the checking of the subclass of object.
issubclass(hw_obj.__class__, HelloWorld)
Example:
from unittest.mock import patch, MagicMock
import unittest
class HelloWorld(object):
def say_it(self):
return 'Hello I am Hello World'
def i_call_hello_world(hw_obj):
print('here... check type: %s' % type(HelloWorld))
if isinstance(hw_obj, HelloWorld) or issubclass(hw_obj.__class__, HelloWorld):
print(hw_obj.say_it())
class TestInstance(unittest.TestCase):
#patch('__main__.isinstance', return_value=True)
def test_mock(self, MK):
print(type(MK))
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print(v)
self.assertTrue(MK.say_it.called)
#patch('__main__.isinstance', return_value=False)
def test_not_call(self, MK):
print(type(MK))
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print(v)
self.assertFalse(MK.say_it.called)
if __name__ == '__main__':
unittest.main()
I came to the same problem.
According to this answer https://stackoverflow.com/a/49718531/11277611
You can't mock the second argument of isinstance()
I don't know the solution but I know a good workaround:
It's good architecture point to hind all checks (like isintanse) inside separate functions because it's not directly related dependency, in most cases you will change the checks but preserve the behavior.
Put isinstance check into separate function and check it separately.
def logic_checks() -> bool:
...
return isinstance(mock, MyMock)
def main_func()
if logic_checks() is not True:
...
...
def test_main_func()
logic_checks = Mock(return_value=True)
main_func()
logic_checks.assert_called_once_with()
...
def test_logic_checks()
... # Here separate checks with another patches, mocks, etc.
Don't use isinstance, instead check for the existence of the say_it method. If the method exists, call it:
if hasattr(hw_obj, 'say_it'):
print hw_obj.say_it()
This is a better design anyway: relying on type information is much more brittle.
I am using mock with Python and was wondering which of those two approaches is better (read: more pythonic).
Method one: Just create a mock object and use that. The code looks like:
def test_one (self):
mock = Mock()
mock.method.return_value = True
self.sut.something(mock) # This should called mock.method and checks the result.
self.assertTrue(mock.method.called)
Method two: Use patch to create a mock. The code looks like:
#patch("MyClass")
def test_two (self, mock):
instance = mock.return_value
instance.method.return_value = True
self.sut.something(instance) # This should called mock.method and checks the result.
self.assertTrue(instance.method.called)
Both methods do the same thing. I am unsure of the differences.
Could anyone enlighten me?
mock.patch is a very very different critter than mock.Mock. patch replaces the class with a mock object and lets you work with the mock instance. Take a look at this snippet:
>>> class MyClass(object):
... def __init__(self):
... print 'Created MyClass#{0}'.format(id(self))
...
>>> def create_instance():
... return MyClass()
...
>>> x = create_instance()
Created MyClass#4299548304
>>>
>>> #mock.patch('__main__.MyClass')
... def create_instance2(MyClass):
... MyClass.return_value = 'foo'
... return create_instance()
...
>>> i = create_instance2()
>>> i
'foo'
>>> def create_instance():
... print MyClass
... return MyClass()
...
>>> create_instance2()
<mock.Mock object at 0x100505d90>
'foo'
>>> create_instance()
<class '__main__.MyClass'>
Created MyClass#4300234128
<__main__.MyClass object at 0x100505d90>
patch replaces MyClass in a way that allows you to control the usage of the class in functions that you call. Once you patch a class, references to the class are completely replaced by the mock instance.
mock.patch is usually used when you are testing something that creates a new instance of a class inside of the test. mock.Mock instances are clearer and are preferred. If your self.sut.something method created an instance of MyClass instead of receiving an instance as a parameter, then mock.patch would be appropriate here.
I've got a YouTube video on this.
Short answer: Use mock when you're passing in the thing that you want mocked, and patch if you're not. Of the two, mock is strongly preferred because it means you're writing code with proper dependency injection.
Silly example:
# Use a mock to test this.
my_custom_tweeter(twitter_api, sentence):
sentence.replace('cks','x') # We're cool and hip.
twitter_api.send(sentence)
# Use a patch to mock out twitter_api. You have to patch the Twitter() module/class
# and have it return a mock. Much uglier, but sometimes necessary.
my_badly_written_tweeter(sentence):
twitter_api = Twitter(user="XXX", password="YYY")
sentence.replace('cks','x')
twitter_api.send(sentence)
Key points which explain difference and provide guidance upon working with unittest.mock
Use Mock if you want to replace some interface elements(passing args) of the object under test
Use patch if you want to replace internal call to some objects and imported modules of the object under test
Always provide spec from the object you are mocking
With patch you can always provide autospec
With Mock you can provide spec
Instead of Mock, you can use create_autospec, which intended to create Mock objects with specification.
In the question above the right answer would be to use Mock, or to be more precise create_autospec (because it will add spec to the mock methods of the class you are mocking), the defined spec on the mock will be helpful in case of an attempt to call method of the class which doesn't exists ( regardless signature), please see some
from unittest import TestCase
from unittest.mock import Mock, create_autospec, patch
class MyClass:
#staticmethod
def method(foo, bar):
print(foo)
def something(some_class: MyClass):
arg = 1
# Would fail becuase of wrong parameters passed to methd.
return some_class.method(arg)
def second(some_class: MyClass):
arg = 1
return some_class.unexisted_method(arg)
class TestSomethingTestCase(TestCase):
def test_something_with_autospec(self):
mock = create_autospec(MyClass)
mock.method.return_value = True
# Fails because of signature misuse.
result = something(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_something(self):
mock = Mock() # Note that Mock(spec=MyClass) will also pass, because signatures of mock don't have spec.
mock.method.return_value = True
result = something(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
class TestSecondTestCase(TestCase):
def test_second_with_autospec(self):
mock = Mock(spec=MyClass)
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
def test_second(self):
mock = Mock()
mock.unexisted_method.return_value = True
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
The test cases with defined spec used fail because methods called from something and second functions aren't complaint with MyClass, which means - they catch bugs, whereas default Mock will display.
As a side note there is one more option: use patch.object to mock just the class method which is called with.
The good use cases for patch would be the case when the class is used as inner part of function:
def something():
arg = 1
return MyClass.method(arg)
Then you will want to use patch as a decorator to mock the MyClass.