I'm trying to mock the django.core.urlresolvers.resolve function, but it doesn't seem to be work. I've tested with custom functions and it works like a charm, but mock ignores resolve completely.
Code:
test_something.py:
class SomethingTestCase(TestCase)
def setUp(self):
self.middleware = SomeMiddleware()
self.request = Mock()
self.request.session = {}
#patch('django.core.urlresolvers.resolve', side_effect=lambda: None)
def test_something(self):
self.assertEqual(self.middleware.process_request(self.request), None)
middleware.py
class SomeMiddleware(object):
def process_request(self, request):
app = resolve(request.path).app_name
print('App name: {}'.format(app))
This results in the following error:
======================================================================
ERROR: test_process_request_unauthenticated (something.tests.unit.test_middleware.SomethingTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/user/virtualenv/something/local/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched
return func(*args, **keywargs)
File "/home/user/projects/something/working/something/tests/unit/test_middleware.py", line 23, in test_process_request_unauthenticated
self.assertEqual(self.middleware.process_request(self.request), None)
File "/home/user/projects/something/working/something/middleware.py", line 14, in process_request
app = resolve(request.path).app_name
File "/home/user/virtualenv/something/local/lib/python2.7/site-packages/django/core/urlresolvers.py", line 534, in resolve
return get_resolver(urlconf).resolve(path)
File "/home/user/virtualenv/something/local/lib/python2.7/site-packages/django/core/urlresolvers.py", line 405, in resolve
raise Resolver404({'path': path})
Resolver404: {u'path': u"<Mock name='mock.path' id='140678271233168'>"}
My goal here is to make the resolve function returns something where I can get the app name.
Why is mock.patch unable to override the resolve function?
Firstly, you are patching it at the wrong location. You should patch it in file it is being used, and not where it is defined as more often than not the target code is imported before the patch is run.
Secondly, if the mocking works it would raise an error something on the lines of NoneType object has no attribute app_name.
#patch(<path_to_middleware.py>, side_effect=lambda: type('mock', (object,), {'app_name': 1})):
def test_something(self):
self.assertEqual(self.middleware.process_request(self.request), None)
Related
I have a model with 2 fields: image (ImageField) and media (FileField). They both use a custom GoogleCloudMediaStorage.
When writing my tests, I cannot access GCS, so I mocked the writing of the files by doing this:
from unittest.mock import patch
#patch('my_project.storage_backends.CustomGoogleCloudMediaStorage.save')
def test(self, mock_save):
mock_save.return_value = 'mocked_file.png'
# rest of the test
And it's working fine. The problem is now I have to test update and list views. When I do so, I have of course this error:
google.auth.exceptions.DefaultCredentialsError: Could not automatically determine credentials. Please set GOOGLE_APPLICATION_CREDENTIALS or explicitly create credentials and re-run the application.
After digging it a bit, I see that the error is triggered by the serializer to_representation(). And more precisely in the FileField:
def to_representation(self, value):
if not value:
return None
use_url = getattr(self, 'use_url', api_settings.UPLOADED_FILES_USE_URL)
if use_url:
try:
url = value.url # !! THIS LINE CAUSE THE ISSUE
except AttributeError:
return None
request = self.context.get('request', None)
if request is not None:
return request.build_absolute_uri(url)
return url
So I tried to mock FileField.to_representation() doing this:
#patch('django.db.models.FileField.to_representation')
def test_update(self, mock_representation):
mock_representation.return_value = 'mocked_training_file_url'
data = {
'title': 'Updated',
}
response = self.client.patch(. . .)
But I have this error:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/unittest/mock.py", line 1322, in patched
with self.decoration_helper(patched,
File "/usr/local/lib/python3.8/contextlib.py", line 113, in __enter__
return next(self.gen)
File "/usr/local/lib/python3.8/unittest/mock.py", line 1304, in decoration_helper
arg = exit_stack.enter_context(patching)
File "/usr/local/lib/python3.8/contextlib.py", line 425, in enter_context
result = _cm_type.__enter__(cm)
File "/usr/local/lib/python3.8/unittest/mock.py", line 1393, in __enter__
original, local = self.get_original()
File "/usr/local/lib/python3.8/unittest/mock.py", line 1366, in get_original
raise AttributeError(
AttributeError: <class 'django.db.models.fields.files.FileField'> does not have the attribute 'to_representation'
Any idea how I can mock FileField and ImageField to_representation() ? Am I doing this correctly
I'm trying to write some unittest for functions that uses openshift python client so I need to mock some openshift client calls.
https://github.com/openshift/openshift-restclient-python
from kubernetes import client, config
from openshift.dynamic import DynamicClient, exceptions as openshift_exceptions
_openshift_cert_manager_api_version = 'cert-manager.io/v1'
class OCPException(Exception):
pass
def certificate_exists(dyn_client: DynamicClient, namespace: str, certificate_name: str) -> bool:
""" Checks if certificate already exists in namespace. """
v1_certificates = dyn_client.resources.get(api_version=_openshift_cert_manager_api_version, kind='Certificate')
try:
v1_certificates.get(namespace=namespace, name=certificate_name)
except openshift_exceptions.NotFoundError:
return False
except openshift_exceptions as Error:
raise OCPException(Error)
return True
import unittest
from unittest import mock
from openshift.dynamic import DynamicClient
from awscertmanager import ocp
class TestCertificateExists(unittest.TestCase):
def test_certificate_exists(self):
mock_client = mock.create_autospec(DynamicClient)
ocp.certificate_exists(mock_client, namespace='dummy', certificate_name='tls-wildcard-dummy')
mock_client.resources.get.assert_called_with(
api_version=ocp._openshift_cert_manager_api_version,
kind='Certificate'
)
if __name__ == '__main__':
unittest.main()
This test works fine with the first call but I've tried to know if the second call (v1_certificates.get) is called with no success.
I've tried mocking Resource class but I get this error.
import unittest
from unittest import mock
from openshift.dynamic import DynamicClient, Resource
from awscertmanager import ocp
class TestCertificateExists(unittest.TestCase):
#mock.patch.object(Resource, 'get')
def test_certificate_exists(self, mock_get):
mock_client = mock.create_autospec(DynamicClient)
ocp.certificate_exists(mock_client, namespace='dummy', certificate_name='tls-wildcard-dummy')
mock_client.resources.get.assert_called_with(
api_version=ocp._openshift_cert_manager_api_version,
kind='Certificate'
)
mock_get.assert_called_with(namespace='dummy', name='tls-wildcard-dummy')
if __name__ == '__main__':
unittest.main()
Error
Traceback (most recent call last):
File "/usr/local/Cellar/python#3.8/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/case.py", line 60, in testPartExecutor
yield
File "/usr/local/Cellar/python#3.8/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/case.py", line 676, in run
self._callTestMethod(testMethod)
File "/usr/local/Cellar/python#3.8/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/case.py", line 633, in _callTestMethod
method()
File "/usr/local/Cellar/python#3.8/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/mock.py", line 1322, in patched
with self.decoration_helper(patched,
File "/usr/local/Cellar/python#3.8/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/contextlib.py", line 113, in __enter__
return next(self.gen)
File "/usr/local/Cellar/python#3.8/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/mock.py", line 1304, in decoration_helper
arg = exit_stack.enter_context(patching)
File "/usr/local/Cellar/python#3.8/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/contextlib.py", line 425, in enter_context
result = _cm_type.__enter__(cm)
File "/usr/local/Cellar/python#3.8/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/mock.py", line 1393, in __enter__
original, local = self.get_original()
File "/usr/local/Cellar/python#3.8/3.8.6_2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/mock.py", line 1366, in get_original
raise AttributeError(
AttributeError: <class 'openshift.dynamic.resource.Resource'> does not have the attribute 'get'
Finally it's working mocking DynamicClient class and some calls:
#mock.patch('awscertmanager.ocp.DynamicClient')
def test_certificate_exists_true(self, mock_dynamicclient):
mock_resource = mock.Mock()
mock_resource.get.return_value = None
mock_dynamicclient.resources.get.return_value = mock_resource
result = ocp.certificate_exists(mock_dynamicclient, namespace=self.namespace, certificate_name=self.certificate_name)
mock_resource.get.assert_called_with(namespace=self.namespace, name=self.certificate_name)
self.assertEqual(result, True)
My first hello world program is not working.
This is my code:
from flask import Flask
app=Flask(__name__)
#app.route('/')
def index():
return "<h1>Hello world</h1>"
if __name__=='__main__':
app.run()
And this is my output:
(myflaskenv) C:\Users\saini computers\Desktop\flask_examples>python
basic.py
Traceback (most recent call last):
File "basic.py", line 6, in <module>
#app.route('/information')
File "C:\Users\saini computers\Anaconda3\envs\myflaskenv\lib\site-
packages\flask\app.py", line 1250, in decorator
self.add_url_rule(rule, endpoint, f, **options)
File "C:\Users\saini computers\Anaconda3\envs\myflaskenv\lib\site-
packages\flask\app.py", line 66, in wrapper_func
return f(self, *args, **kwargs)
File "C:\Users\saini computers\Anaconda3\envs\myflaskenv\lib\site-
packages\flask\app.py", line 1221, in add_url_rule
'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint
function: index
AssertionError: View function mapping is overwriting an existing endpoint function: index
This error indicates that you have used same method name in multiple routes.
You can reproduce the error using the following code:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def index():
return "hello from index"
#app.route("/info")
def index():
return "hello from info"
app.run(debug=True, port=8080)
Error trace:
(venv) ➜ python app.py
Traceback (most recent call last):
File "app.py", line 9, in <module>
#app.route("/info", methods=['GET'])
File ".../app.py", line 1250, in decorator
self.add_url_rule(rule, endpoint, f, **options)
File ".../app.py", line 66, in wrapper_func
return f(self, *args, **kwargs)
File ".../app.py", line 1221, in add_url_rule
'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint function: index
Both routes #app.route("/info") and #app.route("/") use same method called index. So I am getting the error: AssertionError: View function mapping is overwriting an existing endpoint function: index
I think, you are making same mistake. You are using method index for both / and /information route.
As of version 4.x.x, it is now #jwt_required() instead of jwt_required. If you are updating an existing application, you can find a link to all of the breaking changes in the 4.x.x release on the README.
When writing decorators for Flask, you need to decorate the inner wrapper with wraps(func) as described in the official documentation:
A decorator is a function that wraps and replaces another function. Since the original function is replaced, you need to remember to copy the original function’s information to the new function. Use functools.wraps() to handle this for you.
I am trying to write tests for a Flask app.
Currently I have a test that looks like this in a file called test.py.
import mock
from test_helpers import mock_volume_views_setup
class UserTest(unittest.TestCase):
def setUp():
<some set up>
def tearDown():
<some tear down>
#mock.patch('brain_db.views.volume_views_setup')
def test_labeled_scan(self, mock_volume_views_setup):
# test that if path to atlas exists in the container,
self.register_and_commit_user()
self.login_profile_consent()
self.upload('static/test.nii.gz', 1, '04/04/2008', 'GE', '1.5T')
rv = self.app.get('/label_view/1', follow_redirects=True)
response = str(rv.data)
assert "MRI not labeled yet" not in response
test.py lives a top level directory, flask_brain_db.
In flask_brain_db/brain_db/views.py lives the route I'm trying to test. A highly simplified version:
from brain_db_helpers import volume_views_setup
#app.route('/surface_test')
def surface_test():
return render_template('brain_db/surf_view.html')
#app.route('/label_view/<int:scan_number>')
#login_required
def label_view(scan_number):
a, b, c, d = volume_views_setup(scan_number, resource_type='atlas')
if os.path.exists(a):
return render_template('brain_db/scan_view.html')
When I try to run my test, I get
FAIL: test_labeled_scan (test.UserTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/mock/mock.py", line 1297, in patched
arg = patching.__enter__()
File "/usr/local/lib/python2.7/site-packages/mock/mock.py", line 1353, in __enter__
self.target = self.getter()
File "/usr/local/lib/python2.7/site-packages/mock/mock.py", line 1523, in <lambda>
getter = lambda: _importer(target)
File "/usr/local/lib/python2.7/site-packages/mock/mock.py", line 1210, in _importer
thing = _dot_lookup(thing, comp, import_path)
File "/usr/local/lib/python2.7/site-packages/mock/mock.py", line 1199, in _dot_lookup
__import__(import_path)
File "/usr/src/app/flask_brain_db/brain_db/views.py", line 36, in <module>
#app.route('/surface_test')
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1250, in decorator
self.add_url_rule(rule, endpoint, f, **options)
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 66, in wrapper_func
return f(self, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1221, in add_url_rule
'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint function: surface_test
I understand what this error is trying to communicate. Somehow my patch decorator is, in an import, re-executing code that defines the routes in views.py, leading to the error. (The error doesn't appear without the patch decorator and mock function). But I don't understand why, or how I am supposed to patch my helper method. I have really struggled with understanding the correct way to refer to the method that needs patching, but looking at this question for example I think I'm doing it right.
I am using Nick Johnsons Webapp & Templates application as a base for what I am trying to do. I am getting a "AttributeError: 'NoneType' object has no attribute 'write'" when I try to call the render_template. I know it is because when I instantiate the object "Capture" as X, it doesn't have a response property. I have looked everywhere to find a solution but I cannot find one anywhere.
NOTE: There are other ways to do this, but I need it to work as closely to how I have it setup!
Traceback:
Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "/Users/userx/Documents/_FRESHCUTZ MEDIA/Google/GAE - Test web form 1 /testwebform1/main.py", line 41, in post
x.calculateYear(name, age)
File "/Users/userx/Documents/_FRESHCUTZ MEDIA/Google/GAE - Test web form 1 /testwebform1/main.py", line 49, in calculateYear
self.response.write(self.render_template('index.html', **template_args))
AttributeError: 'NoneType' object has no attribute 'write'
MAIN.PY
import os
import webapp2
from webapp2_extras import jinja2
class BaseHandler(webapp2.RequestHandler):
#webapp2.cached_property
def jinja2(self):
return jinja2.get_jinja2(app=self.app)
def render_template(self, filename, **template_args):
self.response.write(self.jinja2.render_template(filename, **template_args))
class MainPage(BaseHandler):
def get(self):
template_args = {}
self.render_template('index.html', **template_args)
class CaptureDetails(BaseHandler):
def post(self):
name = self.request.get("name").strip()
age = self.request.get("age").strip()
x = Calculate()
x.calculateYear(name, age)
class Calculate(BaseHandler):
def calculateYear(self, name, age):
template_args = {"age": age}
self.render_template('name.html', **template_args)
app = webapp2.WSGIApplication([
('/', MainPage),
('/capture', CaptureDetails),
('/age', Calculate)
], debug=True)
What am I doing wrong? Any help/suggestions are greatly appreciated!
Does it fit your criteria if you make calculateYear a function of your BaseHandler class (or elsewhere if more applicable)? As you guessed, your x isn't being treated as a proper response. When you invoke a webapp2.RequestHandler handler, it calls the method associated with the type of request (so in your case, since you are posting a form, it will call post(), as you know). When you instantiate x and call calculateYear, you aren't specifying a particular method (def get(self), def post(self), etc.), so there is no preparation of a response (when I have a chance I'll dig a little to confirm that this is actually the case - I could be mistaken :) ).
Can't test this right now, but assuming you need to call calculateYear from more than just the CaptureDetails handler, would this work? Here you would be referencing self in the context of your post method, which would invoke the response handling:
class BaseHandler(webapp2.RequestHandler):
#webapp2.cached_property
def jinja2(self):
return jinja2.get_jinja2(app=self.app)
def render_template(self, filename, **template_args):
self.response.write(self.jinja2.render_template(filename, **template_args))
def calculateYear(self, name, age):
template_args = {"age": age}
self.render_template('name.html', **template_args)
Which you could then call from your CaptureDetails handler like:
class CaptureDetails(BaseHandler):
def post(self):
name = self.request.get("name").strip()
age = self.request.get("age").strip()
# Call the function and write the response
self.calculateYear(name, age)
By instantiating Calculate yourself in your CaptureDetails.post method you're not creating it in the same way that WSGIApplication does, so the properties aren't available. Specifically, you're not passing a response to it, so not surprisingly trying to reference it doesn't work.
In this case, I'd copy the contents of calculateYear into your post method - you're not really saving anything by having to create the instance and then call the method on it.
If calculateYear gets more complicated, and you don't want the duplication, then I'd introduce a new method that could be called by both of your hander methods. (It's not really clear from this example though why the Calculate class exists - it doesn't have a 'get' method, so mapping it to /age as you have done isn't going to work.)
Try using self.response.out.write instead of self.response.write.