So, I've just started using mock with a Django project. I'm trying to mock out part of a view which makes a request to a remote API to confirm a subscription request was genuine (a form of verification as per the spec I'm working to).
What I have resembles:
class SubscriptionView(View):
def post(self, request, **kwargs):
remote_url = request.POST.get('remote_url')
if remote_url:
response = requests.get(remote_url, params={'verify': 'hello'})
if response.status_code != 200:
return HttpResponse('Verification of request failed')
What I now want to do is to use mock to mock out the requests.get call to change the response, but I can't work out how to do this for the patch decorator. I'd thought you do something like:
#patch(requests.get)
def test_response_verify(self):
# make a call to the view using self.app.post (WebTest),
# requests.get makes a suitable fake response from the mock object
How do I achieve this?
You're almost there. You're just calling it slightly incorrectly.
from mock import call, patch
#patch('my_app.views.requests')
def test_response_verify(self, mock_requests):
# We setup the mock, this may look like magic but it works, return_value is
# a special attribute on a mock, it is what is returned when it is called
# So this is saying we want the return value of requests.get to have an
# status code attribute of 200
mock_requests.get.return_value.status_code = 200
# Here we make the call to the view
response = SubscriptionView().post(request, {'remote_url': 'some_url'})
self.assertEqual(
mock_requests.get.call_args_list,
[call('some_url', params={'verify': 'hello'})]
)
You can also test that the response is the correct type and has the right content.
It's all in the documentation:
patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
target should be a string in the form ‘package.module.ClassName’.
from mock import patch
# or #patch('requests.get')
#patch.object(requests, 'get')
def test_response_verify(self):
# make a call to the view using self.app.post (WebTest),
# requests.get makes a suitable fake response from the mock object
Related
I am trying to mock an HTTP request call using mock because I don't want to Behave to call it actually.
So I have this code scenario in matches.py file:
import request
def get_match():
response = request.get("https://example.com")
return response
And in my step definition match_steps.py for behave I have this:
def logoport_matches_response(context):
mock_response = context.text # this is the payload will come from feature file
with patch ('match') as mock_match:
mock_match.get_match.return_value = {"status": "success"}
But it seems this is not working because it still requesting an actual HTTP request.
I need to mock the get_match method to return {"status": "success"} result
Alright, I figure it out, you need to put your initialization inside the mock so:
from mock import patch
from matches import get_match
with patch ('match') as mock_match:
mock_match.return_value = {"status": "success"}
get_match()
I am writing System Tests for my Django app, where I test the complete application via HTTP requests and mock its external dependencies' APIs.
In views.py I have something like:
from external_service import ExternalService
externalService = ExternalService
data = externalService.get_data()
#crsf_exempt
def endpoint(request):
do_something()
What I want is to mock (or stub) ExternalService to return a predefined response when its method get_data() is called.
The problem is that when I run python manage.py test, views.py is loaded before my test class. So when I patch the object with a mocked one, the function get_data() was already called.
This solution didn't work either.
First off, don't call your method at import time. That can't be necessary, surely?
If get_data does something like a get request, e.g.
def get_data():
response = requests.get(DATA_URL)
if response.ok:
return response
else:
return None
Then you can mock it;
from unittest.mock import Mock, patch
from nose.tools import assert_is_none, assert_list_equal
from external_service import ExternalService
#patch('external_service.requests.get')
def test_getting_data(mock_get):
data = [{
'content': 'Response data'
}]
mock_get.return_value = Mock(ok=True)
mock_get.return_value.json.return_value = data
response = ExternalService.get_data()
assert_list_equal(response.json(), data)
#patch('external_service.requests.get')
def test_getting_data_error(mock_get):
mock_get.return_value.ok = False
response = ExternalService.get_data()
assert_is_none(response)
For this you'll need pip install nose if you don't already have it.
How can I mock a post inside a method, so i can have unittests?
def send_report(self, data):
url = settings.WEBHOOK_PO
payload = json.dumps(data)
requests.post(url, data=payload)
url = settings.WEBHOOK_LQA
response = requests.post(url, data=payload)
return response.status_code
Is there a way to cover this method for unit test with not actually posting?
You can use the mock library to replace requests.post with something else:
with mock.patch('requests.post') as mock_post:
foo.send_report(data)
(mock is a third-party package, but was added to the standard library, as part of the unittest package`, in Python 3.3.)
mock_post can be configured to provide the desired behavior during the test; consult the mock documentation for details.
Another option is to modify your method to take the post function as an argument, rather than hard-coding the function (this is an example of dependency injection):
def send_report(self, data, poster=requests.post):
url = settings.WEBHOOK_PO
payload = json.dumps(data)
poster(url, data=payload)
url = settings.WEBHOOK_LQA
response = poster(url, data=payload)
return response.status_code
When you want to test the function, you simply pass a different callable object as the optional second argument.
Note that you can supply separate functions for the two types of posts, which might make it easier to test than with a mock:
from functools import partial
def send_report(self,
data,
post_po=partial(requests.post, settings.WEBHOOK_PO),
post_lqa=partial(requests.post, settings.WEBHOOK_LQA)):
payload = json.dumps(data)
post_po(data=payload)
response = post_lqa(data=payload)
return response.status_code
I have a piece of code that calls Pyramid's render_to_response. I am not quite sure how to test that piece. In my test, the request object that is sent in is a DummyRequest by Pyramid. How can I capture to_be_rendered.
from pyramid.renderers import render_to_response
def custom_adapter(response):
data = {
'message': response.message
}
to_be_rendered = render_to_response(response.renderer, data)
to_be_rendered.status_int = response.status_code
return to_be_rendered
I believe render_to_response should return a response object. You should be able to call custom_adapter directly in your unit test, providing a DummyRequest and make assertions on the Response object returned by your custom_adapter
def test_custom_adapter(self):
dummy = DummyRequest() # not sure of the object here
response = custom_adapter(dummy)
self.assertEqual(response.status, 200)
In my python code I have global requests.session instance:
import requests
session = requests.session()
How can I mock it with Mock? Is there any decorator for this kind of operations? I tried following:
session.get = mock.Mock(side_effect=self.side_effects)
but (as expected) this code doesn't return session.get to original state after each test, like #mock.patch decorator do.
Since requests.session() returns an instance of the Session class, it is also possible to use patch.object()
from requests import Session
from unittest.mock import patch
#patch.object(Session, 'get')
def test_foo(mock_get):
mock_get.return_value = 'bar'
Use mock.patch to patch session in your module. Here you go, a complete working example https://gist.github.com/k-bx/5861641
With some inspiration from the previous answer and :
mock-attributes-in-python-mock
I was able to mock a session defined like this:
class MyClient(object):
"""
"""
def __init__(self):
self.session = requests.session()
with that: (the call to get returns a response with a status_code attribute set to 200)
def test_login_session():
with mock.patch('path.to.requests.session') as patched_session:
# instantiate service: Arrange
test_client = MyClient()
type(patched_session().get.return_value).status_code = mock.PropertyMock(return_value=200)
# Act (+assert)
resp = test_client.login_cookie()
# Assert
assert resp is None
I discovered the requests_mock library. It saved me a lot of bother. With pytest...
def test_success(self, requests_mock):
"""They give us a token.
"""
requests_mock.get("https://example.com/api/v1/login",
text=(
'{"result":1001, "errMsg":null,'
f'"token":"TEST_TOKEN",' '"expire":1799}'))
auth_token = the_module_I_am_testing.BearerAuth('test_apikey')
assert auth_token == 'TEST_TOKEN'
The module I am testing has my BearerAuth class which hits an endpoint for a token to start a requests.session with.