Python Django: getting started with mocks - python

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.

Related

Check if pytest fixture is called once during testing

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.

Django Mock an imported function used in a class function as part of a unit test

So I'm writing tests for my django application and I have successfully mocked quite a few external api calls that aren't needed for tests however one is tripping me up which is send_sms. To start here is the code:
a/models.py:
from utils.sms import send_sms
...
class TPManager(models.Manager):
def notification_for_job(self, job):
...
send_sms()
...
class TP(models.Model):
objects = TPManager()
...
p/test_models.py:
#patch('a.models.send_sms')
#patch('p.signals.send_mail')
def test_tradepro_review_job_deleted(self, send_mail, send_sms):
job = Job.objects.create(
tradeuser=self.tradeuser,
location=location,
category=category,
details="sample details for job"
)
The Job object creation triggers TP.objects.notification_for_job via its perform_create method here:
p/views.py:
def perform_create(self, serializer):
job = serializer.save(tradeuser=self.request.user.tradeuser)
if settings.DEV_MODE:
from a.models import TP
job.approved = True
job.save()
TP.objects.notification_for_job(job)
I have tried mocking a.models.TP.objects.notification_for_job, utils.sms.send_sms, a.models.TPManger.notification_for_job all to no avail. This is a pretty complex flow but I believe I have tried the main mock candidates here and was wondering if anybody knows how to either mock the notification_for_job function or send_sms function properly mostly just to prevent these api call that inevitably fail due to my test environment.
Any ideas are greatly appreciated!

How to mock the get function from requests.session?

I am trying to mock the get function from requests.session and somehow it does not end up happening.
I have the following code:
#main.py
import requests
def function_with_get():
c = requests.session()
c.get('https://awesome_url.com')
# do some other stuff
return c
def second_function_with_get(client):
c.get('https://awesome_url.com')
# do some other stuff
#test.py
from unittest import mock
from django.test import TestCase
class Testing(TestCase):
#mock.patch('main.requests.session.get)
#mock.patch('main.requests.session)
def test_which_fails_because_of_get(mock_sess, mock_get):
client = function_with_get()
second_function_with_get(client)
assertEqual(mock_requests_session_get.call_count, 2)
The test throws an assertion error that mock_get is called 0 times (0 != 2)
How should the get function of requests.session() be mocked?
It seems that you are already mocking the requests session - since it is a MagicMock, you don't need to additionally mock the get method itself - checking for calls on the session will be enough.
So, your test.py could look like this:
#test.py
from unittest import mock
from unittest import TestCase
from main import function_with_get, second_function_with_get
class Testing(TestCase):
#mock.patch('main.requests.session')
def test_which_fails_because_of_get(self, mock_sess):
client = function_with_get()
second_function_with_get(client)
self.assertEqual(mock_sess.return_value.get.call_count, 2)
You could also try to create your own SessionMock class with the get method mocked, but it would require also proper setting (or resetting) it for each test. Personally, I usually find using MagicMock and its return_value chain easier.

Python3 Unittest Mocking Requests Module

I am comfortable using dependancy injection with Java's Mockito library, but have little experience using Python3's unittest.mock module. I am trying to assert that the Request instance's prepare method gets called. However the test fails on the assertion self.assertTrue(mock_request.prepare.called). Can someone please advise me on how to get this test passing?
import requests
import unittest
from unittest import mock
class Engine(object):
def get(self, **kwargs):
session = requests.Session()
req = requests.Request('GET', 'http://www.google.com', params=kwargs).prepare()
response = session.send(req, timeout=1)
class TestEngine(unittest.TestCase):
#mock.patch('requests.Session')
#mock.patch('requests.Request')
def test_get(self, mock_request, mock_session):
e = Engine()
e.get()
self.assertTrue(mock_request.called)
self.assertTrue(mock_request.prepare.called)
if __name__ == '__main__':
unittest.main()
Your code never accesses prepare on Request directly. The method is accessed on the return value of a call to Request(), so test for that instead by using the Mock.return_value attribute:
self.assertTrue(mock_request.return_value.prepare.called)
When debugging mock issues, I find it helpful to print out the Mock.mock_calls attribute for the top-level mock object; for your test printing mock_request.mock_calls produces:
[call('GET', 'http://www.google.com', params={}), call().prepare()]
showing that call().prepare() was indeed accessed (and the result of a call() is usually accessible via the Mock.return_value attribute, as shown above).

unit test to check if for a given path a correct context will be returned

Just like in the title. I have a model that I can test manually. I enter url in a browser and receive a result form one of the views. Thing is unittest should be doing that.
I think there should be some way to create a request, send it to the application and in return receive the context.
You can create functional tests using the WebTest package, which allows you to wrap your WSGI application in a TestApp that supports .get(), .post(), etc.
See http://docs.pylonsproject.org/projects/pyramid/1.0/narr/testing.html#creating-functional-tests for specifics in Pyramid, pasted here for posterity:
import unittest
class FunctionalTests(unittest.TestCase):
def setUp(self):
from myapp import main
app = main({})
from webtest import TestApp
self.testapp = TestApp(app)
def test_root(self):
res = self.testapp.get('/', status=200)
self.failUnless('Pyramid' in res.body)
Pyramid doesn't really expose a method for testing a real request and receiving information about the internals. You possible execute the traverser yourself using:
from pyramid.traversal import traverse
app = get_app(...)
root = get_root(app)
out = traverse(root, '/my/test/path')
context = out['context']
However, the test is a bit contrived. It'd be more relevant to use a functional test that checks if the returned page is what you expect.

Categories