mock patch fails for some reason - python

I'm trying to patch an API for unit testing purposes. I have a class like this:
# project/lib/twilioclient.py
from os import environ
from django.conf import settings
from twilio.rest import TwilioRestClient
def __init__(self):
return super(Client, self).__init__(
settings.TWILIO_ACCOUNT_SID,
settings.TWILIO_AUTH_TOKEN,
)
client = Client()
and this method:
# project/apps/phone/models.py
from project.lib.twilioclient import Client
# snip imports
class ClientCall(models.Model):
'call from Twilio'
# snip model definition
def dequeue(self, url, method='GET'):
'''"dequeue" this call (take off hold)'''
site = Site.objects.get_current()
Client().calls.route(
sid=self.sid,
method=method,
url=urljoin('http://' + site.domain, url)
)
and then the following test:
# project/apps/phone/tests/models_tests.py
class ClientCallTests(BaseTest):
#patch('project.apps.phone.models.Client', autospec=True)
def test_dequeued(self, mock_client):
cc = ClientCall()
cc.dequeue('test', 'TEST')
mock_client.calls.route.assert_called_with(
sid=cc.sid,
method='TEST',
url='http://example.com/test',
)
When I run the test, it fails because the real client is called instead of the mock client.
Looks like it should work to me, and I've been able to make this type of thing work before. I've tried the usual suspects (removing *.pyc) and things don't seem to be changing. Is there a new behavior here that I'm missing somehow?

Related

how to do unit test for functions inside of Resource class in flask-restful?

I am quite new to unit testing and relatively new to RESTful API development as well. I am wondering how to do unit test for functions inside Resource class in flask restful? I can do unit test for the endpoint's response but I don't know how to do testing for the individual functions inside the endpoint's controller class.
Below is my application code. It has 3 files including test:
api.py
controller_foo.py
test_controller_foo.py
# api.py
from flask import Flask
from flask_restful import Api
from .controller_foo import ControllerFoo
def create_app(config=None):
app = Flask(__name__)
app.config['ENV'] ='development'
return app
application = app = create_app()
api = Api(app)
api.add_resource(ControllerFoo, '/ctrl')
if __name__ == "__main__":
app.run(debug=True)
# controller_foo.py
from flask_restful import Resource
from flask import request
class ControllerFoo(Resource):
"""
basically flask-restful's Resource method is a wrapper for flask's MethodView
"""
def post(self):
request_data = self.handle_request()
response = self.process_request(request_data)
return response
def handle_request(self):
json = request.get_json()
return json
def process_request(self, data):
# do some stuffs here
return {'foo': 'bar'}
I am using unittest
# test_controller_foo.py
import unittest
from api import app
from .controller_foo import ControllerFoo
# initiating class to try testing but I don't know how to start
ctrl = ControllerFoo()
class ControllerFooTestCase(unittest.TestCase):
def setUp(self):
self.app = app
self.app.config['TESTING'] = True
self.client = app.test_client()
self.payload = {'its': 'empty'}
def tearDown(self):
pass
def test_get_response(self):
response = self.client.post('/ctrl', json=self.payload)
expected_resp = {
'foo': 'bar'
}
self.assertEqual(response.status_code, 200)
self.assertDictEqual(response.get_json(), expected_resp)
if __name__ == "__main__":
unittest.main()
I want to know how to properly do unit test for handle_request and process_request function
EDIT: Fixing out my buggy code. Thanks Laurent LAPORTE for the highlights.
There are several bugs in your code, so this is not easy to explain.
First of all, the recommended way to do testing with Flask (and Flask-Restful) is to use PyTest instead of unittest, because it is easier to setup and use.
Take a look at the documentation: Testing Flask Applications.
But, you can start with unittest…
note: you can have a confusion with your app module and the app instance in that module. So, to avoid it, I imported the module. Another good practice is to name your test module against the tested module: "app.py" => "test_app.py". You can also have a confusion with the controller module and the controller instance. The best practice is to use a more precise name, like "controller_foo" or something else…
Here is a working unit test:
# test_app.py
import unittest
import app
class ControllerTestCase(unittest.TestCase):
def setUp(self):
self.app = app.app
self.app.config['TESTING'] = True
self.client = self.app.test_client()
self.payload = {'its': 'empty'}
def test_get_response(self):
response = self.client.post('/ctrl', json=self.payload)
expected_resp = {'foo': 'bar'}
self.assertEqual(response.status_code, 200)
self.assertDictEqual(response.get_json(), expected_resp)
if __name__ == "__main__":
unittest.main()
As you can see, I also fixed the posted URL, in your application, the URL is "/ctrl", not "controller".
At this point, the test can run, but you have another error:
Ran 1 test in 0.006s
FAILED (errors=1)
Error
Traceback (most recent call last):
...
TypeError: process_request() takes 1 positional argument but 2 were given
If you take a look at your process_request() method, you can see that you missed the self parameter. Change it like this.
def process_request(self, data):
# do some stuffs here
return {'foo': 'bar'}
Your test should pass.
But, that not the right way to implement Flask-Restful controolers. Read the doc and use get and post methods…

Can I have an abstract base class for my tornado.testing.AsyncTestCase tests?

Is it possible to have base classes that define tests in tornado that are themselves not run as tests?
Let's say I have the following minimal example as a base class:
from tornado.testing import AsyncTestCase, gen_test
from tornado.httpclient import HTTPRequest
class AbstractTestCase(AsyncTestCase):
def set_parameters(self):
#Set some parameter value here: self.uri = ...
raise NotImplementedError
#gen_test
def test_common_functionality(self):
req = HTTPRequest(self.uri, method = "GET")
response = yield self.client.fetch(req, raise_error=False)
self.assertEqual(200, response.code)
Now, I would like to make several test cases that inherit from this, define their own value for self.uri...and have some specific tests of their own. Like this:
class ConcreteTestCase(AbstractTestCase):
def set_parameters(self):
self.uri = "www.stackoverflow.com"
#gen_test
def test_some_other_thing(self):
self.assertEqual(2, 1+1)
However, when I try to run this, the AbstractTestCase is also run on its own, giving an error (the NotImplementedError). This happens even when I only try to run the inheriting tests.
Is there any way around this issue, or do I have to duplicate the functionality in each test case?
One way to do this is with multiple inheritance. The abstract class doesn't need to extend AsyncTestCase as long as that class is in the inheritance hierarchy at runtime.
class AbstractTestCase(object):
def set_parameters(self):
#Set some parameter value here: self.uri = ...
raise NotImplementedError
#gen_test
def test_common_functionality(self):
req = HTTPRequest(self.uri, method = "GET")
response = yield self.client.fetch(req, raise_error=False)
self.assertEqual(200, response.code)
class ConcreteTestCase(AbstractTestCase, AsyncTestCase):
def set_parameters(self):
self.uri = "www.stackoverflow.com"
#gen_test
def test_some_other_thing(self):
self.assertEqual(2, 1+1)
This is admittedly a little weird and mypy type checking doesn't like it. But it's simple and it works, and I haven't found a mypy-friendly alternative that I like.
CLI
python3 -m tornado.testing ConcreteTestCase.ConcreteTestCase
testmain.py
#!/usr/bin/env python3
import unittest
from tornado.testing import main
def all():
cases = ['ConcreteTestCase.ConcreteTestCase']
return unittest.defaultTestLoader.loadTestsFromNames(cases)
main()
test/runtests.py is a good example.

Python Django: getting started with mocks

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.

Can't mock the class method in python

I have a class that I try to mock in tests. The class is located in server/cache.py and looks like:
class Storage(object):
def __init__(self, host, port):
# set up connection to a storage engine
def store_element(self, element, num_of_seconds):
# store something
def remove_element(self, element):
# remove something
This class is used in server/app.py similar to this one:
import cache
STORAGE = cache.Storage('host', 'port')
STORAGE.store_element(1, 5)
Now the problem arise when I try to mock it in the tests:
import unittest, mock
import server.app as application
class SomeTest(unittest.TestCase):
# part1
def setUp(self):
# part2
self.app = application.app.test_client()
This clearly does not work during the test, if I can't connect to a storage. So I have to mock it somehow by writing things in 'part1, part2'.
I tried to achieve it with
#mock.patch('server.app.cache') # part 1
mock.side_effect = ... # hoping to overwriting the init function to do nothing
But it still tries to connect to a real host. So how can I mock a full class here correctly? P.S. I reviewed many many questions which look similar to me, but in vain.

tornado testing #tornado.web.authenticated

I'm trying to test tornado using AsyncHTTPTestCase. I want to test handlers marked with the #tornado.web.authenticated annotation. Because this handler requires authentication we must login first or somehow fool it in thinking we are authenticated in our test code
class HandlerToTest(BaseHandler):
#tornado.web.authenticated
def get(self):
self.render("hello.html", user=self.get_current_user() )
According to this article we can fudge the cookies. I have got this working but according to Ben Darnell tornado maintainer this is not recommended. Ben recommends using the CookieLib module but that requires the 'info' part of the response which we don't have.
Another blog post suggests mocking the get_current_user() call using mox. However I can not get the sample code in the blog working.
So my question is:
What is the best way of testing the handlers marked as authenticated? And can someone point me to a sample application?
Eventually got Mocks working. Don't know if this is the 'best way' but it might be useful to someone in the future. This code tests 2 handlers and mocks the get_current_user() call generated by #tornado.web.authenticated:
# encoding: utf-8
import os, os.path, sys
import tornado.web
import tornado.testing
import mox
class BaseHandler(tornado.web.RequestHandler):
def get_login_url(self):
return u"/login"
def get_current_user(self):
user_json = self.get_secure_cookie("user")
if user_json:
return tornado.escape.json_decode(user_json)
else:
return None
class HelloHandler(BaseHandler):
#tornado.web.authenticated
def get(self):
self.render("protected.html")
class Protected(tornado.web.RequestHandler):
def get_current_user(self):
# get an user from somewhere
return "andy"
#tornado.web.authenticated
def get(self):
self.render("protected.html")
class TestAuthenticatedHandlers(tornado.testing.AsyncHTTPTestCase):
def get_app(self):
self.mox = mox.Mox()
app = tornado.web.Application([
(r'/protected', Protected),
(r'/hello', HelloHandler)
])
return app
def tearDown(self):
self.mox.UnsetStubs()
self.mox.ResetAll()
def test_new_admin(self):
self.mox.StubOutWithMock(Protected, 'get_current_user', use_mock_anything=True)
Protected.get_current_user().AndReturn("test_user")
self.mox.ReplayAll()
resp = self.fetch('/protected')
self.assertEqual(resp.code, 200)
self.mox.VerifyAll()
def test_hello_page(self):
self.mox.StubOutWithMock(HelloHandler, 'get_current_user', use_mock_anything=True)
HelloHandler.get_current_user().AndReturn("test_user")
self.mox.ReplayAll()
resp = self.fetch('/hello')
self.assertEqual(resp.code, 200)
self.assertIn( "Hello", resp.body )
self.mox.VerifyAll()
This Torando utils library also allows you to test authenticated handlers: tornado_utils/http_test_client.py
In my case simply works:
BaseHandler.get_current_user = lambda x: {'username': 'user', 'email': 'user#ex.com'}

Categories