I am trying to write a unit test for a class that looks like below.
import boto
class ToBeTested:
def location(self, eb):
return eb.create_storage_location()
def some_method(self):
eb = boto.beanstalk.connect_to_region(region, access_key, secret_key)
location(eb)
Is there a way to mock boto.beanstalk.connect_to_region return value and finally mocking create_storage_location? I am new to patch and mock in python, so I have no idea how could I go about doing that. Could someone please let me know if there is a way to do this?
Thanks much!
The idea is to patch connect_to_region() so that it returns a Mock object, then you can define whatever methods you want on the mock, example:
import unittest
from mock import patch, Mock
class MyTestCase(unittest.TestCase):
#patch('boto.beanstalk.connect_to_region')
def test_boto(self, connect_mock):
eb = Mock()
eb.create_storage_location.return_value = 'test'
connect_mock.return_value = eb
to_be_tested = ToBeTested()
# assertions
See also:
An Introduction to Mocking in Python
Hope that helps.
Related
Does pytest provides functionality like unittest.mock to check if the mock was actually called once(or once with some parameter)?
Sample Source code:
my_package/my_module.py
from com.abc.validation import Validation
class MyModule:
def __init__(self):
pass
def will_call_other_package(self):
val = Validation()
val.do()
def run(self):
self.will_call_other_package()
Sample test code for the above source code:
test_my_module.py
import pytest
from pytest_mock import mocker
from my_package.my_module import MyModule
#pytest.fixture
def mock_will_call_other_package(mocker):
mocker.patch('my_package.my_module.will_call_other_package')
#pytest.mark.usefixtures("mock_will_call_other_package")
class TestMyModule:
def test_run(self):
MyModule().run()
#check `will_call_other_package` method is called.
#Looking for something similar to what unittest.mock provide
#mock_will_call_other_package.called_once
If you want to use a fixture that does the patching, you can move the patching into a fixture:
import pytest
from unittest import mock
from my_package.my_module import MyModule
#pytest.fixture
def mock_will_call_other_package():
with mock.patch('my_package.my_module.will_call_other_package') as mocked:
yield mocked
# the mocking will be reverted here, e.g. after the test
class TestMyModule:
def test_run(self, mock_will_call_other_package):
MyModule().run()
mock_will_call_other_package.assert_called_once()
Note that you have to use the fixture parameter in the test. Just using #pytest.mark.usefixtures will not give you access to the mock itself. You can still use it to be effective in all tests in the class, if you don't need to access the mock in all tests (or use autouse=True in the fixture).
Also note that you don't need pytest-mock here - but as mentioned by #hoefling, using it makes the fixture better readable, because you don't need the with clause :
#pytest.fixture
def mock_will_call_other_package(mocker):
yield mocker.patch('my_package.my_module.will_call_other_package')
As an aside: you don't need to import mocker. Fixtures are looked up by name, and available automatically if the respective plugin is installed.
You could try this:
import pytest
from my_package.my_module import MyModule
def test_run(mocker):
mocker.patch('my_package.my_module.will_call_other_package')
MyModule().run()
mock_will_call_other_package.assert_called_once()
First of all, you may not need the burden of an external library such as pytest_mock, because pytest already got you covered using the integration with unittest.
You also do not need to use the usefixtures because whenever you need a fixture, you just receive it in your test method.
An ideal scenario based on your own code would look similar to this:
import pytest
from unittest.mock import patch
from com.abc.validation import Validation
class MyModule:
def __init__(self):
pass
def will_call_other_package(self):
val = Validation()
val.do()
def run(self):
self.will_call_other_package()
#pytest.fixture
def call_other_module():
with patch("my_package.my_module.MyModule.will_call_other_package") as _patched:
yield _patched
class TestMyModule:
def test_run_will_call_other_package(self, call_other_module):
call_other_module.assert_not_called()
obj = MyModule()
call_other_module.assert_not_called()
obj.run()
call_other_module.assert_called_once()
And also if you want to make sure that you did infact patch the target MyModule.will_call_other_package, modify your test like this:
class TestMyModule:
def test_run_will_call_other_package(self, call_other_module):
call_other_module.assert_not_called()
obj = MyModule()
call_other_module.assert_not_called()
obj.run()
call_other_module.assert_called_once()
assert False, (MyModule.will_call_other_package, call_other_module)
And you'll see something similar to this:
AssertionError: (<MagicMock name='will_call_other_package' id='140695551841328'>, <MagicMock name='will_call_other_package' id='140695551841328'>)
As you can see the id of both objects are the same, confirming our experiment was successful.
I am having hard times with unittest mock and patch. I'd like to test a specific class and change some attributes in it.
I think that I have a path problem but can't figure how to resolve it.
#lib.inventory.py
class Inventory(object):
def __init__(self):
self.db = "12"
def do_stuff(self):
return "ok"
#test.py
import unittest
from mock import patch
import time
from lib.inventory import Inventory
#test_case.py
class MyTest(unittest.TestCase):
#patch('lib.inventory.Inventory')
def test_retrieve_project_id(self,mock_inventory):
print "####################"
print Inventory
print mock_inventory
print "####################"
When I run this test I should see that both Inventory and mock_inventory objects points to the same MagickMock Object. But it isn't the case :
####################
<class 'lib.inventory.Inventory'>
<MagicMock name='Inventory' id='140594977874320'>
####################
Could you tell me what I am doing wrong ?? Maybe I have misanderstood mock and patch concept ?
Thank you
Example abc.py:
from pack.def import Def
class Abc(object):
def f(self):
return Def().response()
Example test_abc.py
from unittest import mock, TestCase
from pack.abc import Abc
class TestAbc(TestCase):
#mock.patch('pack.def.Def')
def test_f(self, mock_def):
responses = ['response1', 'response2', 'response3']
mock_def.return_value.response.return_value = responses
assert responses == Abc().f()
I assumed the mock def has been patched, but I'm doing something wrong, does someone know I'm doing wrong?
You must mock the object your are working. You are using the Def that belongs to pack.def package in abc module. When you write test for Abc class, and want to mock Def calls, you must mock the Def that is imported in abc, not from original module.
Use #mock.patch('pack.abc.Def') instead of #mock.patch('pack.def.Def').
I have the following code that I'm attempting to create a test (still work in progress):
from core.tests import BaseTestCase
from core.views import get_request
from entidades.forms import InstituicaoForm
from mock import patch
class InstituicaoFormTestCase(BaseTestCase):
def setUp(self):
super(InstituicaoFormTestCase, self).setUp()
#patch('get_request', return_value={'user': 'usuario_qualquer'})
def test_salva_instituicao_quando_informaram_convenio():
import pdb
pdb.set_trace()
form = InstituicaoForm()
it fails because when I try to create a InstituicaoForm, a get_request is called:
def get_request():
return getattr(THREAD_LOCAL, 'request', None)
and it trows this error
entidades/tests.py:11: in <module>
class InstituicaoFormTestCase(BaseTestCase):
entidades/tests.py:16: in InstituicaoFormTestCase
#patch('get_request', return_value={'user': 'usuario_qualquer'})
.tox/unit/local/lib/python2.7/site-packages/mock/mock.py:1670: in patch
getter, attribute = _get_target(target)
.tox/unit/local/lib/python2.7/site-packages/mock/mock.py:1522: in _get_target
(target,))
E TypeError: Need a valid target to patch. You supplied: 'get_request'
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /home/vinicius/telessaude/.tox/unit/local/lib/python2.7/site-packages/mock/mock.py(1522)_get_target()
-> (target,))
What am I doing wrong? How should mock this get_request() method?
I think the specific thing you're trying to do can be done like this:
#patch('core.views.get_request', return_value={'user': 'usuario_qualquer'})
But you should also look at the Django testing documentation, if you haven't already. You can use the testing client to fake the web request.
If you want to experiment with mock tests that don't access a database, check out Django Mock Queries. (I'm a small contributor to that project.) I've also tried mocking views, but it's fiddly.
I have the following Python unit test case.
import json
import rules
from rules import RULES
import models
from django.test import TestCase
from mock import patch
class RulesTest(TestCase):
request_length = 484
url = "http://www.ndtv.com"
def setUp(self):
har_data = open('/Users/rokumar/SiteAnalysisGit/Src/hct/exportfiles/test.har')
self.data = json.load(har_data)
self.rule = models.Rule(name=RULES.DNS,user=None,
threshold=None)
self.rule.save()
def tearDown(self):
self.rule.delete()
def test_parse_har(self):
with patch.object(rules, 'add_dns_analysis', return_value=None) as \
dns_mock:
dns_mock.add_dns_analysis('test result', 'test url')
result = rules.parse_har(self.data,[self.rule],RulesTest.url)
self.assertEqual(result[RULES.TOTAL_REQUESTS], 484)
Can I mock the add_dns_analysis method using #patch decorator instead of context manager and when should I use either of them.
In your case you can use either decorator and context and even patch instead of patch.object. For instance your test could be rewrite as
#patch.object(rules, 'add_dns_analysis', return_value=None)
def test_parse_har(self,dns_mock):
dns_mock.add_dns_analysis('test result', 'test url')
result = rules.parse_har(self.data,[self.rule],RulesTest.url)
self.assertEqual(result[RULES.TOTAL_REQUESTS], 484)
or
#patch('rules.add_dns_analysis', return_value=None)
def test_parse_har(self,dns_mock):
dns_mock.add_dns_analysis('test result', 'test url')
result = rules.parse_har(self.data,[self.rule],RulesTest.url)
self.assertEqual(result[RULES.TOTAL_REQUESTS], 484)
EDIT
I wrote that answer by thing the question was When to use... instead of How to use.... So the next part is about When to use the patch decorator to patch a method instead of using it with context manager.
But in general by decorator you can obtain cleaner code than the context version. For instance if need to patch more object the decorator version looks like
#patch('amodule.A.a_method')
#patch('amodule.A.b_method')
#patch('amodule.B.c_method')
def test_mytest(self,bc_mock,ab_mock,aa_mock):
...
but the context version looks like:
#patch('amodule.A.a_method')
#patch('amodule.A.b_method')
#patch('amodule.B.c_method')
def test_mytest(self):
with patch('amodule.A.a_method') as aa_mock:
with patch('amodule.A.b_method') as ab_mock:
with patch('amodule.B.c_method') as bc_mock:
....
I think that in that case decorator's version is real better.
patch decorator is powerful but not a silver bullet. For instance if in your test you need configure something in your patch that depend from other object or your class you can't use decorator:
def mytest(self):
foo = Foo()
with patch('amodule.A.a_method', return_value=self.a_return, my_property=foo) as m:
...
The last example where you have to use with instead of patch is when you need more one patch of the same object in the same test or you need both patched and unpatched version:
def mytest(self):
with patch('amodule.A.a_method', return_value="first") as m:
....
with patch('amodule.A.a_method', return_value="second") as m:
....
amodule.A.a_method() #original
Finally you can obtain a complete fine grain by a direct use of enter() exit() methods of the patch object but I think that is a little bit out of scope in that answer.
Yes, you could use #patch decorator. In my opinion, there is no big difference between both decisions.