I'm trying to migrate to py.test for the ease of use and auto-discovery of tests. When I run my tests with unittest, the test works fine. When I run the test under py.test, I get RuntimeError: working outside of application context
.
Here's the test code (test_app.py):
import unittest
from app import app
class TestAPILocally(unittest.TestCase):
def setUp(self):
self.client = app.test_client()
def testRoot(self):
retval = self.client.get('/').data
self.assertTrue('v1' in retval)
if __name__ == '__main__':
unittest.main()
And here's the stripped down file I'm testing (app.py):
from flask import Flask
from flask.ext.restful import Api, Resource
class APIListAPI(Resource):
def get(self):
return ['v1']
app = Flask(__name__)
api = Api(app)
api.add_resource(APIListAPI, '/')
As you can see, this is very similar to the docs on the flask site: the testing skeleton, and indeed, when I run it with unittest, it succeeds:
$ python tmp1/test_app.py
.
----------------------------------------------------------------------
Ran 1 test in 0.115s
OK
$
But, when I test with py.test, it fails:
$ ./py.test tmp1/test_app.py
=================== test session starts =========================
platform sunos5 -- Python 2.7.5 -- py-1.4.22 -- pytest-2.6.0
collected 1 items
tmp1/test_app.py F
========================= FAILURES ==============================
_________________ TestAPILocally.testRoot _______________________
self = <tmp1.test_app.TestAPILocally testMethod=testRoot>
def testRoot(self):
> retval = self.client.get('/').data
tmp1/test_app.py:10:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
werkzeug/test.py:762: in get
return self.open(*args, **kw)
flask/testing.py:108: in open
follow_redirects=follow_redirects)
werkzeug/test.py:736: in open
response = self.run_wsgi_app(environ, buffered=buffered)
werkzeug/test.py:659: in run_wsgi_app
rv = run_wsgi_app(self.application, environ, buffered=buffered)
werkzeug/test.py:855: in run_wsgi_app
app_iter = app(environ, start_response)
tmp1/flask/app.py:1836: in __call__
return self.wsgi_app(environ, start_response)
tmp1/flask/app.py:1820: in wsgi_app
response = self.make_response(self.handle_exception(e))
flask_restful/__init__.py:256: in error_router
if self._has_fr_route():
flask_restful/__init__.py:237: in _has_fr_route
if self._should_use_fr_error_handler():
flask_restful/__init__.py:218: in _should_use_fr_error_handler
adapter = current_app.create_url_adapter(request)
werkzeug/local.py:338: in __getattr__
return getattr(self._get_current_object(), name)
werkzeug/local.py:297: in _get_current_object
return self.__local()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def _find_app():
top = _app_ctx_stack.top
if top is None:
> raise RuntimeError('working outside of application context')
E RuntimeError: working outside of application context
flask/globals.py:34: RuntimeError
================ 1 failed in 1.02 seconds ======================
Now, it turns out, I can make this test pass just by doing this:
$ rm tmp1/__init__.py
And make it fail again by doing this:
$ touch tmp1/__init__.py
So, is there some difference between the way that unittest and py.test handles files in modules? It seems very strange that it breaks enough to make Flask complain, as I clearly am in an app context calling app.test_client().get(). Is this expected behavior, or should I file a bug against py.test?
In case it's relevant, the reason I'm executing the tests from the parent directory is because I don't have the ability to add modules to site-packages, so I'm initiating all my code from the parent directory, where I've installed Flask, py.test, etc.
Edit: Solved. It was an installation problem. Adding pythonpath tag, since that was the solution.
RuntimeError: Working outside of application context. This typically means that you attempted to use functionality that needed to interface with the current application object in some way. To solve this, set up an application context with app. app_context().
Flask automatically pushes an application context when handling a request. View functions, error handlers, and other functions that run during a request will have access to current_app . Flask will also automatically push an app context when running CLI commands registered with Flask. cli using @app.
The request context keeps track of the request-level data during a request. Rather than passing the request object to each function that runs during a request, the request and session proxies are accessed instead.
current_app is function in Flask's flask. globals module and is an instance of LocalProxy from the Werkzeug framework. current_app can be used to access data about the running application, including the configuration. This is useful for both developers using the framework and ones building extensions for Flask.
Not directly answer to TS question, but mostly for 'application context' error.
Adding pushing and poping context in setUp and tearDown functions should help with this error:
def setUp(self):
self.app_context = app.app_context()
self.app_context.push()
def tearDown(self):
self.app_context.pop()
You can find more info on flask context there:
also in this awesome article by Daniel Kronovet:
PS If you planning to use url_for in tests, additional configuration required:
@classmethod
def setUpClass(cls)
app.config['SERVER_NAME'] = 'localhost:5000'
class ViewsTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
app.config['SERVER_NAME'] = 'localhost:5000'
cls.client = app.test_client()
def setUp(self):
self.app_context = app.app_context()
self.app_context.push()
def tearDown(self):
self.app_context.pop()
def test_view_should_respond(self):
r = self.client.get(url_for("index"))
self.assertEqual(r.status_code, 200)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With