What is mocking in Python?
What is mocking in unit testing?
There are several questions regarding this library that I need help understanding with.
-
What is the purpose of unittest.mock? How does it differ from unittest? Can one test just based on unittest without unittest.mock (or vice versa)?
-
What is a mock? Why are they used? Why are they important? What are the benefits of them versus just importing class objects from other user-defined modules to test?
-
How does the patch decorator work?
Please keep answers as rudimentary as possible.
You can use patch() as a class decorator, not just as a function decorator. You can then pass in the mocked function as before:
@patch('mymodule.SomeClass')
class MyTest(TestCase):
def test_one(self, MockSomeClass):
self.assertIs(mymodule.SomeClass, MockSomeClass)
See: Applying the same patch to every test method (which also lists alternatives)
It makes more sense to set up the patcher this way on setUp if you want the patching to be done for all the test methods.
I'll start by answering your questions, and then I'll give a detailed example of how patch() and setUp() interact.
- I don't think it looks right, see my answer to question #3 in this list for details.
- Yes, the actual call to patch looks like it should mock the object you want.
- No, you almost never want to use the
@patch()decorator onsetUp(). You got lucky, because the object is created insetUp()and never gets created during the test method. - I don't know of any way to make a mock object raise an exception without importing that exception into your test case file.
- I don't see any need for
patch.object()here. It just lets you patch attributes of an object instead of specifying the target as a string.
To expand on my answer to question #3, the problem is that the patch() decorator only applies while the decorated function is running. As soon as setUp() returns, the patch is removed. In your case, that works, but I bet it would confuse someone looking at this test. If you really only want the patch to happen during setUp(), I would suggest using the with statement to make it obvious that the patch is going to be removed.
The following example has two test cases. TestPatchAsDecorator shows that decorating the class will apply the patch during the test method, but not during setUp(). TestPatchInSetUp shows how you can apply the patch so that it's in place during both setUp() and the test method. Calling self.addCleanUp() makes sure that the patch will be removed during tearDown().
import unittest
from mock import patch
@patch('__builtin__.sum', return_value=99)
class TestPatchAsDecorator(unittest.TestCase):
def setUp(self):
s = sum([1, 2, 3])
self.assertEqual(6, s)
def test_sum(self, mock_sum):
s1 = sum([1, 2, 3])
mock_sum.return_value = 42
s2 = sum([1, 2, 3])
self.assertEqual(99, s1)
self.assertEqual(42, s2)
class TestPatchInSetUp(unittest.TestCase):
def setUp(self):
patcher = patch('__builtin__.sum', return_value=99)
self.mock_sum = patcher.start()
self.addCleanup(patcher.stop)
s = sum([1, 2, 3])
self.assertEqual(99, s)
def test_sum(self):
s1 = sum([1, 2, 3])
self.mock_sum.return_value = 42
s2 = sum([1, 2, 3])
self.assertEqual(99, s1)
self.assertEqual(42, s2)