I'm trying to test with Flask-Testing a Flask-SQLAlchemy model. More precisely a static method of this model that uses first_or_404()
and I cannot find a way to make my test work.
Here a self contained example that highlight the issue:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask.ext.testing import TestCase
db = SQLAlchemy()
class ModelToTest(db.Model):
__tablename__ = 'model_to_test'
identifier = db.Column(db.String(80), unique=True, nullable=False, primary_key=True)
@staticmethod
def get_by_identifier(identifier):
return ModelToTest.query.filter_by(identifier=identifier).first_or_404()
class Config:
DEBUG = True
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///'
SQLALCHEMY_TRACK_MODIFICATIONS = False
class TestGetByIdentifier(TestCase):
def create_app(self):
app = Flask('test')
app.config.from_object(Config())
db.init_app(app)
return app
def setUp(self):
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
def test_get_by_identifier(self):
self.assert404(ModelToTest.get_by_identifier('identifier'))
I got the error:
(my_env) PS C:\Dev\Test\Python\test_flask> nosetests-3.4.exe
E
======================================================================
ERROR: test_get_by_identifier (test_flask.TestGetByIdentifier)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Dev\Test\Python\test_flask\test_flask.py", line 37, in test_get_by_identifier
self.assert404(ModelToTest.get_by_identifier('identifier'))
File "C:\Dev\Test\Python\test_flask\test_flask.py", line 13, in get_by_identifier
return ModelToTest.query.filter_by(identifier=identifier).first_or_404()
File "c:\\my_env\lib\site-packages\flask_sqlalchemy\__init__.py", line 431, in first_or_404
abort(404)
File "c:\\my_env\lib\site-packages\werkzeug\exceptions.py", line 646, in __call__
raise self.mapping[code](*args, **kwargs)
werkzeug.exceptions.NotFound: 404: Not Found
----------------------------------------------------------------------
Ran 1 test in 0.913s
So the line self.assert404(ModelToTest.get_by_identifier('identifier'))
does generate an exception in the first_or_404()
call and this exception is a werkzeug.exceptions.NotFound
, it does not seems to be what's expected by self.assert404()
.
Requirements to run this test are:
It is worth noting that when I use the function in the application it behaves as expected.
Thanks in advance.
I'm quoting the answer I've received on GitHub:
https://github.com/jarus/flask-testing/issues/89
I believe this is a misunderstanding about the way to drive the test. The
first_or_404
function will indeed raise aNotFound
exception. When in the context of the request, the exception will bubble up, be handled, and turn into a 404 http response, which is what flask-testing is looking for.However, you are not in the context of a request in this case since you are calling the method directly and it is simply resulting in an exception. You could do this to make the test work
from werkzeug.exceptions import NotFound def test_get_by_identifier(self): with self.assertRaises(NotFound): ModelToTest.get_by_identifier('identifier')
Or, you can stick that function behind a route and test it using self.client which will correctly give you a 404 http response. However, testing the exception (without the use of flask-testing) may be more appropriate in this case given the level you are testing at.
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