Mocking dependencies - python

I am Python newbie and trying to understand how to mock methods in UTs.
Here is my Test
test_module2.py
from module2 import A
import unittest
from unittest.mock import patch, MagicMock
class TestBulkLoad(unittest.TestCase):
#patch('simple_module.SimpleModuleClass')
def test_fun(self, a):
a.simpleFun = MagicMock(return_value=3)
testA = A()
testA.fun()
assert a.simpleFun.called
and I want to check that dependent SimpleModuleClass was mocked and invoked
module2.py
from simple_module import SimpleModuleClass
class A:
def fun(self):
print('I am from A class')
thing = SimpleModuleClass()
thing.simpleFun()
return -1
simple_module.py
class SimpleModuleClass:
def simpleFun(self):
print("I am from SimpleModuleClass")
return 0
I get AssertionError. Could you help me understand how to fix this?

a.simpleFun = MagicMock(return_value=3)
This line is only modifying the method of your mock object a (which you really should rename simpleModuleMock, since it's a mock of a SimpleModule class and not an A). It doesn't mock every instance of SimpleModule everywhere in your code, hence why an instance of SimpleModule is instantiated in A.fun() and not an instance of a mock of SimpleModule.
I would use dependency injection and pass an instance of SimpleModule to A.fun() instead of instantiating it inside of it, so that you can pass a mock. You could also make thing a public variable like so:
test_module2.py:
class TestBulkLoad(unittest.TestCase):
#patch('simple_module.SimpleModuleClass')
def test_fun(self, simpleModuleMock):
simpleModuleMock.simpleFun = MagicMock(return_value=3)
testA = A()
A.thing = simpleModuleMock
assert(testA.fun() == -1)
# assert simpleModule.simpleFun.called
assert isinstance(simpleModuleMock.simpleFun, MagicMock)
module2.py:
class A:
thing = SimpleModuleClass()
def fun(self):
print('I am from A class')
self.thing.simpleFun()
return -1
Note that there may exist better solutions with Python, but if there are, 1. I don't know of them, and 2. I doubt they're good practice.

Related

Python unittest: Unable to mock imported functions so that conditional evaluates to False

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)

Unable to mock class methods using unitest in python

module a.ClassA:
class ClassA():
def __init__(self,callingString):
print callingString
def functionInClassA(self,val):
return val
module b.ClassB:
from a.ClassA import ClassA
class ClassB():
def __init__(self,val):
self.value=val
def functionInsideClassB(self):
obj=ClassA("Calling From Class B")
value=obj.functionInClassA(self.value)
Python unittest class
import unittest
from b.ClassB import ClassB
from mock import patch, Mock, PropertyMock,mock
class Test(unittest.TestCase):
#patch('b.ClassB.ClassA',autospec = True)
def _test_sample(self,classAmock):
dummyMock=Mock()
dummyMock.functionInClassA.return_value="mocking functionInClassA"
classAmock.return_value=dummyMock
obj=ClassB("dummy_val")
obj.functionInsideClassB()
assert dummyMock.functionInClassA.assert_called_once_with("dummy_val")
The assertion fails. Where exactly am I going wrong?
You assigned to return_value twice:
classAmock.return_value=dummyMock
classAmock.return_value=Mock()
That second assignment undoes your work setting up dummyMock entirely; the new Mock instance has no functionInClassA attribute set up.
You don't need to create new mock objects; just use the default return_value attribute value:
class Test(unittest.TestCase):
#patch('b.ClassB.ClassA', autospec=True)
def test_sample(self, classAmock):
instance = classAmock.return_value
instance.functionInClassA.return_value = "mocking functionInClassA"
obj = ClassB("dummy_val")
obj.functionInsideClassB()
instance.functionInClassA.assert_called_once_with("dummy_val")
You do not need to assert the return value of assert_called_once_with() as that is always None (making your extra assert fail, always). Leave the assertion to the assert_called_once_with() method, it'll raise as needed.

What is the canonical way to check if a function has been called in Python unittest without use of a mock?

If I have a class similar to the 1 below and I want to test the various cases for the bar function, how can I accomplish this without mocking the private functions? In other words, how in Python's unittest library could I achieve something similar to this:
def test_bar():
f = Foo()
f.bar(3)
expect(self._is_positive_number).toBeCalled()
foo.py
class Foo():
def bar(self, x):
if type(x) is not int:
print('Please enter a valid integer')
return False
if x > 0:
self._is_positive_number()
elif x == 0:
self._is_zero()
else
self._is_negative()
def _is_positive_number(self):
print('Positive')
return True
def _is_zero(self):
print('Zero')
return True
def _is_negative_number(self):
print('Negative')
return True
As far as I know, there's no way to do this without mocking out the private methods. However, the mock library (available as unittest.mock in the standard library as of 3.3, a separate installation otherwise) makes this relatively painless:
try:
# Python 3.3 or later
import unittest.mock as mock
except ImportError:
# Make sure you install it first
import mock
class TestFoo(unittest.TestCase):
def setUp(self):
self.f = Foo()
def test_bar(self):
with mock.patch.object(self.f, '_is_positive_number') as is_pos:
self.f.bar(3)
self.assertTrue(is_pos.called)
Using mock library is a preferred way to go.
Here's a complete example for all three private methods. You can choose shorter names if you prefer, but I'd better stay explicit. Note that, to be safe, you should assert that not only a desired method was called, but that other private methods weren't called:
from unittest import TestCase
from mock import Mock
class MyTestCase(TestCase):
def setUp(self):
self.instance = Foo()
self.instance._is_positive_number = Mock()
self.instance._is_negative_number = Mock()
self.instance._is_zero = Mock()
def test_positive(self):
self.instance.bar(3)
self.assertTrue(self.instance._is_positive_number.called)
self.assertFalse(self.instance._is_negative_number.called)
self.assertFalse(self.instance._is_zero.called)
def test_negative(self):
self.instance.bar(-3)
self.assertFalse(self.instance._is_positive_number.called)
self.assertTrue(self.instance._is_negative_number.called)
self.assertFalse(self.instance._is_zero.called)
def test_zero(self):
self.instance.bar(0)
self.assertFalse(self.instance._is_positive_number.called)
self.assertFalse(self.instance._is_negative_number.called)
self.assertTrue(self.instance._is_zero.called)

Testing Private Methods in Python: Unit Test or Functional Test?

After reading about testing private methods in Python, specifically referring to this accepted answer, it appears that it is best to just test the public interface. However, my class looks like this:
class MyClass:
def __init__(self):
# init code
def run(self):
self.__A()
self.__B()
self.__C()
self.__D()
def __A(self):
# code for __A
def __B(self):
# code for __B
def __C(self):
# code for __C
def __D(self):
# code for __D
Essentially, I created a class to process some input data through a pipeline of functions. In this case, it would be helpful to test each private function in turn, without exposing them as public functions. How does one go about this, if a unit test can't execute the private function?
Python does some name mangling when it puts the actually-executed code together. Thus, if you have a private method __A on MyClass, you would need to run it like so in your unit test:
from unittest import TestCase
class TestMyClass(TestCase):
def test_private(self):
expected = 'myexpectedresult'
m = MyClass()
actual = m._MyClass__A
self.assertEqual(expected, actual)
The question came up about so-called 'protected' values that are demarcated by a single underscore. These method names are not mangled, and that can be shown simply enough:
from unittest import TestCase
class A:
def __a(self):
return "myexpectedresult"
def _b(self):
return "a different result"
class TestMyClass(TestCase):
def test_private(self):
expected = "myexpectedresult"
m = A()
actual = m._A__a()
self.assertEqual(expected, actual)
def test_protected(self):
expected = "a different result"
m = A()
actual = m._b()
self.assertEqual(expected, actual)
# actual = m._A__b() # Fails
# actual = m._A_b() # Fails
First of all, you CAN access the "private" stuff, can't you? (Or am I missing something here?)
>>> class MyClass(object):
... def __init__(self):
... pass
... def __A(self):
... print('Method __A()')
...
>>> a=MyClass()
>>> a
<__main__.MyClass object at 0x101d56b50>
>>> a._MyClass__A()
Method __A()
But you could always write a test function in MyClass if you have to test the internal stuff:
class MyClass(object):
...
def _method_for_unit_testing(self):
self.__A()
assert <something>
self.__B()
assert <something>
....
Not the most elegant way to do it, to be sure, but it's only a few lines of code at the bottom of your class.
Probably you should just test the run() method. Most classes will have internal methods -- and it does not really matter in this case whether or not all the code in __A(), __B(), __C,() and __D() is actually in run() or not. If you suspect or find problems, then you might want to switch to your debugger aspect and test the private methods.

Mocking a class: Mock() or patch()?

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.

Categories

Resources