Test Django Mock - check that function/method is called - django

I want to check that do_a calls do_b. I'm doing like this:
The code:
def do_a(...):
...
do_b(...)
...
The test:
def test_do_a(self):
...
with patch('...do_b', new_callable=do_nothing()) as mock_do_b:
do_a(...)
mock_do_b.assert_called_once_with(...)
And do_nothing:
def do_nothing():
pass
This is working fine but I had to use do_nothing() which I find hacky. Is there a way to make the same test without the extra useless function do_nothing()?

You could use patch as a decorator
#patch('...do_b')
def test_do_a(self, mock_do_b):
do_a(...)
mock_do_b.assert_called_once_with(...)

Related

How to mock.patch a dependancy in Python?

Mocking a method that is a dependancy is not working for me. When the method I need to test is calling its dependancy method, the real method is called instead of the mock version of it.
I do have the following files:
myLibrary.py
from src.myOtherLibrary import myOtherLibrary
class myLibrary():
def __init__():
self.myVar = myOtherLibrary() #dependancy
def my_method():
method1 = self.method1()
externalMethod2 self.myVar.method2() #method2 called from the external class myOtherLibrary
return method1 + externalMethod2
def method1():
return "method1 from myLibrary..."
src/myOtherLibrary.py
class myOtherLibrary():
def method2():
return "method2 from myOtherLibrary..."
Finally the Unit Test:
TestMyLibrary.py
import unittest
import mock
from myLibrary import myLibrary
from src.myOtherLibrary import myOtherLibrary
class TestMyLibrary(unittest.TestCase):
#mock.patch('myLibrary.myLibrary.method1') #mocking this works because it's a sibling method from my_method() to test
#mock.patch('src.myOtherLibrary.myOtherLibrary.method2') #this does not work because it's an external class from myLibrary
def test_my_method(my_method1_to_mock, my_method2_to_mock):
my_method1_to_mock.return_value = "something_to_return.."
my_method2_to_mock.return_value = "something_else_to_return.."
myLibraryVar = myLibrary()
result = myLibraryVar.my_method()
print result #I would expect to see this: "something_to_return..something_else_to_return.."
#But it actually prints this: "something_to_return..method2 from myOtherLibrary..."
#So mocking is not working for method2
self.assertEqual('something_to_return..something_else_to_return..', result)
if __name__ == '__main__':
unittest.main()
Perhaps it's important to mention that myLibrary.py and TestMyLibrary.py are in the same folder, but myOtherLibrary.py is under different folder level.
I hope you can help me find what I'm missing here.
Any suggestion will be very well appreciated.
Thanks.
You can't patch like that because the methods you are trying to mock are class methods not functions. So you need to use patch.object.
#mock.patch.object(myLibrary, 'method1')
#mock.patch.object(myOtherLibrary, 'method2')
...

request issue when unit-testing webapp2 with mock and patch

I'm building unit tests for this webapp2 handler (built for GAE)
class PushNotificationHandler(webapp2.RequestHandler):
def post(self):
UserNotification.parse_from_queue(self.request)
return
app = webapp2.WSGIApplication([
(r'/push/notification', PushNotificationHandler),
], debug=True)
One test is
#patch.object(UserNotification, 'parse_from_queue')
def test_post_webapp(self, p_parse_from_queue):
response = webtest.TestApp(app).post('/push/notification')
eq_(response.status_int, 200)
p_parse_from_queue.assert_called_once_with(response.request)
The HTTP reply is OK, but the mock assertion fails:
Expected call: parse_from_queue(<TestRequest at 0x105a89850 POST http://localhost/push/notification>)
Actual call: parse_from_queue(<Request at 0x105a89950 POST http://localhost/push/notification>)
I can't understand why the request is not the correct one (looks like a deep copy). Is there anything wrong with the unit-test, or is that the way webapp2 handle requests. In the second case, is there a way to test it, without creating a separate test to test PushNotificationHandler.post()
Thanks
I've used mock's call_args in a similar situation. You can do something like this:
request = p_parse_from_queue.call_args[0][0]
self.assertEqual(request.url, "foo")
self.assertEqual(request.*, *)
The [0][0] gives you the first passed argument assuming that you are using ordered arguments and not keyword arguments.
You can then proceed to check other relevant attributes of the request object to make sure it is behaving as expected.

python3 mock.assert_called_once_with on changing list [duplicate]

Consider example:
def func_b(a):
print a
def func_a():
a = [-1]
for i in xrange(0, 2):
a[0] = i
func_b(a)
And test function that tries to test func_a and mocks func_b:
import mock
from mock import call
def test_a():
from dataTransform.test import func_a
with mock.patch('dataTransform.test.func_b', autospec=True) as func_b_mock:
func_a()
func_b_mock.assert_has_calls([call(0), call(1)])
After func_a has executed I try to test if func_a made correct calls to func_b, but since in for loop I am mutating list in the end I get:
AssertionError: Calls not found.
Expected: [call(0), call(1)]
Actual: [call([1]), call([1])]
The following works (the importing mock from unittest is a Python 3 thing, and module is where func_a and func_b are):
import mock
from mock import call
import copy
class ModifiedMagicMock(mock.MagicMock):
def _mock_call(_mock_self, *args, **kwargs):
return super(ModifiedMagicMock, _mock_self)._mock_call(*copy.deepcopy(args), **copy.deepcopy(kwargs))
This inherits from MagicMock, and redefines the call behaviour to deepcopy the arguments and keyword arguments.
def test_a():
from module import func_a
with mock.patch('module.func_b', new_callable=ModifiedMagicMock) as func_b_mock:
func_a()
func_b_mock.assert_has_calls([call([0]), call([1])])
You can pass the new class into patch using the new_callable parameter, however it cannot co-exist with autospec. Note that your function calls func_b with a list, so call(0), call(1) has to be changed to call([0]), call([1]). When run by calling test_a, this does nothing (passes).
Now we cannot use both new_callable and autospec because new_callable is a generic factory but in our case is just a MagicMock override. But Autospeccing is a very cool mock's feature, we don't want lose it.
What we need is replace MagicMock by ModifiedMagicMock just for our test: we want avoid to change MagicMock behavior for all tests... could be dangerous. We already have a tool to do it and it is patch, used with the new argument to replace the destination.
In this case we use decorators to avoid too much indentation and make it more readable:
#mock.patch('module.func_b', autospec=True)
#mock.patch("mock.MagicMock", new=ModifiedMagicMock)
def test_a(func_b_mock):
from module import func_a
func_a()
func_b_mock.assert_has_calls([call([0]), call([1])])
Or:
#mock.patch("mock.MagicMock", new=ModifiedMagicMock)
def test_a():
with mock.patch('module.func_b') as func_b_mock:
from module import func_a
func_a()
func_b_mock.assert_has_calls([call([0]), call([1])])

Mock object issue

I am using mock from voidspace and trying to execute some tests using unittest2 and the behaviour is strange. When i use "#patch.object(Test,'asd')" as a patch i get the mock object in the function arguments.
If i use #patch.object(Test,'asd',new_fun) as patch i dont get the one of the parameters.
I am using mock-1.0.1
Here you can see a small sample of code that exemplifies the problem.
I want to try to understand if this issue is a problem with the way i do the patch or if this is a problem in the library.
import unittest2 as unittest
from mock import patch
class Test:
def asd(self, a, b =""):
print "1"
class Test1:
def kk(self, l):
Test().asd("1")
def kk1(self, l):
Test().asd("1","1")
#patch.object(Test,'asd')
class MockClassUT(unittest.TestCase):
def test_stat_process(self, my_mock):
t = Test1()
def test_stat_process1(self, my_mock):
t = Test1()
def test_stat_process2(self, my_mock):
t = Test1()
def new_fun(*args, **kwargs):
print "1"
#patch.object(Test,'asd',new_fun)
class MockClassUT1(unittest.TestCase):
def test_stat_process(self, my_mock):
t = Test1()
t.kk("1")
my_mock.assert_called_with("k")
testloader = unittest.TestLoader()
testnames = testloader.getTestCaseNames(MockClassUT)
suite = unittest.TestSuite()
for name in testnames:
suite.addTest(MockClassUT(name))
testnames = testloader.getTestCaseNames(MockClassUT1)
for name in testnames:
suite.addTest(MockClassUT1(name))
print testnames
unittest.TextTestRunner(verbosity=2).run(suite)
This is expected behaviour. You have mocked it as a class decorator and you've also specified the new function new_fun. As such the mocked object won't be passed to each of the methods in the test class.
This means you can't expect my_mock as parameter there and it also means you can't write assertions using my_mock.
Furthermore, as an aside, your mocked method new_fun doesn't have the same signature as the method you're mocking (asd). The method asd expects self, a, b="" whereas new_fun doesn't have arguments so I expect an issue to come up there as well when the mocked method is called.

Unmocking a mocked object in Django unit tests

I have several TestCase classes in my django application. On some of them, I mock out a function which calls external resources by decorating the class with #mock.patch, which works great. One TestCase in my test suite, let's call it B(), depends on that external resource so I don't want it mocked out and I don't add the decorator. It looks something like this:
#mock.patch("myapp.external_resource_function", new=mock.MagicMock)
class A(TestCase):
# tests here
class B(TestBase):
# tests here which depend on external_resource_function
When I test B independently, things work as expected. However, when I run both tests together, A runs first but the function is still mocked out in B. How can I unmock that call? I've tried reloading the module, but it didn't help.
Patch has start and stop methods. Based on what I can see from the code you have provided, I would remove the decorator and use the setUp and tearDown methods found in the link in your classes.
class A(TestCase):
def setUp(self):
self.patcher1 = patch('myapp.external_resource_function', new=mock.MagicMock)
self.MockClass1 = self.patcher1.start()
def tearDown(self):
self.patcher1.stop()
def test_something(self):
...
>>> A('test_something').run()
Great answer. With regard to Ethereal's question, patch objects are pretty flexible in their use.
Here's one way to approach tests that require different patches. You could still use setUp and tearDown, but not to do the patch.start/stop bit.
You start() the patches in each test and you use a finally clause to make sure they get stopped().
Patches also support Context Manager stuff so that's another option, not shown here.
class A(TestCase):
patcher1 = patch('myapp.external_resource_function', new=mock.MagicMock)
patcher2 = patch('myapp.something_else', new=mock.MagicMock)
def test_something(self):
li_patcher = [self.patcher1]
for patcher in li_patcher:
patcher.start()
try:
pass
finally:
for patcher in li_patcher:
patcher.stop()
def test_something_else(self):
li_patcher = [self.patcher1, self.patcher2]
for patcher in li_patcher:
patcher.start()
try:
pass
finally:
for patcher in li_patcher:
patcher.stop()