Patch - Patching the class introduces an extra parameter? - python

First time using patch. I've tried to patch one of my classes for testing. Without the patch attempting to run gets past the test function definition, but with the patch the test function definition apparently requires another parameter and I get a
TypeError: testAddChannelWithNamePutsChannel() takes exactly 1 argument (2 given)
Error. The test code is the following:
import unittest
import mock
from notification.models import Channel, addChannelWithName, deleteChannelWithName
class TestChannel(unittest.TestCase):
#mock.patch('notification.models.Channel')
def testAddChannelWithNamePutsChannel(self):
addChannelWithName('channel1')
Channel.put.assert_called_with()
Why does it require an extra parameter with the patch and what should this parameter be? Thank you much!

Patch passes in an instance of the patched object to your test method (or to every test method if you are patching at the class level). This is handy because it lets you set return values and side effects, or check the calls made
from unittest.mock import patch
#patch('some_module.sys.stdout')
def test_something_with_a_patch(self, mock_sys_stdout):
mock_sys_stdout.return_value = 'My return value from stdout'
my_function_under_test()
self.assertTrue(mock_sys_stdout.called)
self.assertEqual(output, mock_sys_stdout.return_value)
If you just want to literally patch something out to ignore it then you can call patch with the following invocation
from unittest.mock import patch, Mock
#patch('some_module.sys.stdout', Mock())
def test_something_with_a_patch(self):
That replaces sys.stdout in the some_module with a Mock object and does not pass it to the method.

patch passes the patched object to the test function. Its documented here:
patch as function decorator, creating the mock for you and passing it
into the decorated function:
>>>
>>> #patch('__main__.SomeClass')
... def function(normal_argument, mock_class):
... print(mock_class is SomeClass)
...
>>> function(None)
True

Related

pytest can't mock a method when its called by another module

I can't seem to mock a method of one of my modules. I can mock it inside the unit test itself, but not in another method that calls it.
# Inside a module
from my_module import my_method
def some_method_that_calls_my_module_my_method(arg):
my_method(arg)
# In my unit test
#patch("my_module.my_method", mock.MagicMock(return_value="test1"))
def test_test():
# this works
print(my_module.my_method("slkdjflskdjfl"))
# this executes the method not the mock
some_method_that_calls_my_module_my_method("sldkfjlskdjflskdjf")
I'll add I really want to use the pytest decorator here if I can- I much prefer it to with.

pytest - using patch as a decorator to patch a constant

I have an object MyObject which uses a constant defined in mymodule.constants.MYCONSTANT. I can successfully patch the constant using a context manger like so:
import pytest
from unittest.mock import patch
def test_constant(self):
with patch('mymodule.constants.MYCONSTANT', 3):
MyObject()
However, I can't figure out how to use the equivalent patching using patch as a decorator:
#patch('mymodule.constants.MYCONSTANT', 3)
def test_constant(self, mock_constant):
MyObject()
The above fails with a fixture mock_constant not found error. I tried using
#patch('mymodule.constants.MYCONSTANT', return_value=3)
But MYCONSTANT doesn't get replaced with the value of 3.
This is aligned to the behavior as documented:
unittest.mock.patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
... If patch() is used as a decorator and new is omitted, the created mock is passed in as an extra argument to the decorated function.
So, if you want to pass the extra argument to the decorated function, don't set the new argument:
#patch('mymodule.constants.MYCONSTANT')
def test_constant(self, mock_constant):
...
Setting the new argument means no extra argument would be passed:
#patch('mymodule.constants.MYCONSTANT', 3)
def test_constant(self):
...
Guys the order of parameters matter so first mocks then fixtures, otherwise it will still throw you the same error.
#patch('server.app.UserValidator')
def test_first_mocks(self,mock_user_validator:MagicMock,client_fixture:FlaskClient):
# Arrange
input = {'password':'internal','username':'error'}
mock_user_validator.side_effect = ValueError('testing')
# Act
response = client_fixture.post('/api/users',json=input)
# Assert
mock_user_validator.assert_called_once()
assert response.status_code == 500

Pass parameter to side_effect function for patching in unittest.mock

I'm using patch from unittest.mock to change the behavior of a remote API call in my test.
I have three different functions that return three different json files that represent the mock data to be returned from the API. For each mock api call, I am setting side_effect to be one of these functions. This pattern isn't DRY, but I don't know how to pass a parameter to a side_effect function.
The three mock api call functions look like this:
def mock_api_call_1():
with open('path/to/mock_1.json') as f:
mock_data = json.load(f)
return mock_data
Here's my test
class MyTest(TestCase):
def test_api(self):
with patch('mymodule.utils.api_call', side_effect=mock_api_call_1):
do_crud_operations()
self.assertEqual(MyModel.objects.all().count(), 10)
with patch('mymodule.utils.api_call', side_effect=mock_api_call_2):
do_crud_operations()
self.assertEqual(MyModel.objects.all().count(), 11)
How can I refactor this code to be able to pass a parameter to the side_effect (mock_call(1) instead of mock_call_1).
From the unittest docs, I see that:
side_effect: A function to be called whenever the Mock is called. See
the side_effect attribute. Useful for raising exceptions or
dynamically changing return values. The function is called with the
same arguments as the mock, and unless it returns DEFAULT, the return
value of this function is used as the return value.
I see that the function passed to side_effect takes the same arguments as the mock, but I'm still not sure how best to use mock to accomplish this. I'll eventually want to add more test cases, so I don't want to be hard-coding different mock_api_call functions.
Use a lambda function:
from unittest import TestCase, main
from unittest.mock import Mock, patch
import sys
def mock_api_call(x):
print(x)
class MyTest(TestCase):
def test_api(self):
with patch('sys.exit',
side_effect=lambda x: mock_api_call(x)) as m:
m(0)
sys.exit(0)
m(1)
sys.exit(1)
if __name__ == '__main__':
main()
I think the easiest way to do this is to set side_effect to a function that returns a function.
def mock_call(num):
def wrapper():
with open("path/to/mock_{num}.json") as f:
data = json.load(f)
return data
return wrapper
Now I can pass mock_call(1) to side_effect and it will behave as expected.

Why is mock.patch class decorator not working?

I want to mock something for an entire class but the following minimal example is not working:
import time
import six
if six.PY2:
import mock
else:
from unittest import mock
#mock.patch('time.sleep', mock.Mock(side_effect=Exception('dooooom')))
class Foo(object):
def bar(self):
print('before')
time.sleep(1)
print('after')
f = Foo()
f.bar()
I get this unexpected output: (why did time.sleep not raise?)
before
after
However if I move the #mock.patch(...) down 1 line so it is decorating the method bar instead of the class Foo then it works as expected:
before
...
Exception: blah
Why does #mock.patch not work at the class level?
It turns out the class decorator only patches methods beginning with patch.TEST_PREFIX which defaults to test.
So renaming the method to test_bar or even testbar makes the patch start working.
Docs:
Patch can be used as a TestCase class decorator. It works by decorating each test method in the class. This reduces the boilerplate code when your test methods share a common patchings set. patch() finds tests by looking for method names that start with patch.TEST_PREFIX. By default this is 'test', which matches the way unittest finds tests. You can specify an alternative prefix by setting patch.TEST_PREFIX.
Evidently this behaviour applies to any class whether inheriting from unittest.TestCase or not.

Python unittest: to mock.patch() or just replace method with Mock?

When mocking classes or methods when writing unittests in Python, why do I need to use #patch decorator? I just could replace the method with Mock object without any patch annotation.
Examples:
class TestFoobar(unittest.TestCase):
def setUp(self):
self.foobar = FooBar()
# 1) With patch decorator:
#patch.object(FooBar, "_get_bar")
#patch.object(FooBar, "_get_foo")
def test_get_foobar_with_patch(self, mock_get_foo, mock_get_bar):
mock_get_bar.return_value = "bar1"
mock_get_foo.return_value = "foo1"
actual = self.foobar.get_foobar()
self.assertEqual("foo1bar1", actual)
# 2) Just replacing the real methods with Mock with proper return_value:
def test_get_foobar_with_replacement(self):
self.foobar._get_foo = Mock(return_value="foo2")
self.foobar._get_bar = Mock(return_value="bar2")
actual = self.foobar.get_foobar()
self.assertEqual("foo2bar2", actual)
Could someone produce an example, where patch decorator is good and replacing is bad?
We have always used patch decorator with our team, but after reading this comment for a post, I got the idea that maybe we could write nicer-looking code without the need of patch decorators.
I understand that patching is temporary, so maybe with some cases, it is dangerous to not use patch decorator and replace methods with mock instead? Could it be that replacing objects in one test method can affect the result of the next test method?
I tried to prove this, but came up empty: both tests pass in the next code:
def test_get_foobar_with_replacement(self):
self.foobar._get_foo = Mock(return_value="foo2")
self.foobar._get_bar = Mock(return_value="bar2")
actual = self.foobar.get_foobar()
self.assertIsInstance(self.foobar._get_bar, Mock)
self.assertIsInstance(self.foobar._get_foo, Mock)
self.assertEqual("foo2bar2", actual)
def test_get_foobar_with_real_methods(self):
actual = self.foobar.get_foobar()
self.assertNotIsInstance(self.foobar._get_bar, Mock)
self.assertNotIsInstance(self.foobar._get_foo, Mock)
self.assertIsInstance(self.foobar._get_bar, types.MethodType)
self.assertIsInstance(self.foobar._get_foo, types.MethodType)
self.assertEqual("foobar", actual)
Full source code (Python 3.3): dropbox.com/s/t8bewsdaalzrgke/test_foobar.py?dl=0
patch.object will restore the item you patched to its original state after the test method returns. If you monkey-patch the object yourself, you need to restore the original value if that object will be used in another test.
In your two examples, you are actually patching two different things. Your call to patch.object patches the class FooBar, while your monkey patch patches a specific instance of FooBar.
Restoring the original object isn't important if the object will be created from scratch each time. (You don't show it, but I assume self.foobar is being created in a setUp method, so that even though you replace its _get_foo method, you aren't reusing that specific object in multiple tests.)

Categories

Resources