jwanglof
jwanglof

Reputation: 547

I'm lost with trying to write tests to my Flask application

So I've tried writing some tests for my Flask application for a couple of days but I can't get it to run. The tests pass but it gets stuck on PASSED.

I've cloned cookiecutter-flask (cookiecutter-flask) and it runs webtest together with pytest (I think). My conftest.py looks the same as it does in the repo (conftest.py)

These are my current tests:

def test_app(testapp):
    app = create_app(TestConfig)
    res = testapp.get('/')
    res.status_code == 200

This pass and it continues.

def test_create_admin_user(db, testapp):
    password = bcrypt.generate_password_hash('test')

    User.create(
        uid='00000000000000000000',
        email='[email protected]',
        password=password,
        active=1
    )

    user = User.query.filter_by(email='[email protected]').first()

    assert user.email == '[email protected]'

This is where I'm lost and the test gets stuck on PASSED and doesn't do anything. When I force interrupt the process I get this:

Traceback (most recent call last):
  File "manage.py", line 68, in <module>
    manager.run()
  File "/home/johan/Development/venv_python/local/lib/python2.7/site-packages/flask_script/__init__.py", line 412, in run
    result = self.handle(sys.argv[0], sys.argv[1:])
  File "/home/johan/Development/venv_python/local/lib/python2.7/site-packages/flask_script/__init__.py", line 383, in handle
    res = handle(*args, **config)
  File "/home/johan/Development/venv_python/local/lib/python2.7/site-packages/flask_script/commands.py", line 216, in __call__
    return self.run(*args, **kwargs)
  File "/home/johan/Development/venv_python/local/lib/python2.7/site-packages/flask/ctx.py", line 386, in __exit__
    self.auto_pop(exc_value)
  File "/home/johan/Development/venv_python/local/lib/python2.7/site-packages/flask/ctx.py", line 374, in auto_pop
    self.pop(exc)
  File "/home/johan/Development/venv_python/local/lib/python2.7/site-packages/flask/ctx.py", line 357, in pop
    % (rv, self)
AssertionError: Popped wrong request context.  (<RequestContext 'http://localhost/' [GET] of backend.app> instead of <RequestContext 'http://localhost/' [GET] of backend.app>)

I've found the following thread in flask about testing (granted, this is Flask-Testing but I thought that it has some relevance, maybe it doesn't: issue) and changed my test-config so it contains PRESERVE_CONTEXT_ON_EXCEPTION = False but it still just hangs.

Anybody have any ideas I can try? I'm not super familiar with testing per se so it probably is something that I'm doing wrong.

Upvotes: 5

Views: 2094

Answers (2)

Jaza
Jaza

Reputation: 3226

The db fixture provided by flask-cookiecutter is prone to locking up, and this is probably what's hanging your tests (this was the case for me when I first started writing tests for a flask-cookiecutter based app).

Here's a better db fixture (to replace the one in your tests/conftest.py file):

@pytest.yield_fixture(scope='function')
def db(app):
    _db.app = app
    with app.app_context():
        _db.session.remove()
        _db.drop_all()
        _db.create_all()

    yield _db

    _db.session.remove()
    _db.drop_all()

    ## This dispose() call is needed to avoid the DB locking
    ## between tests.
    ## Thanks to:
    ## http://stackoverflow.com/a/18293157/2066849
    _db.get_engine(_db.app).dispose()

Could also be an issue with the app context, but that isn't prone to completely hang the tests as much as the DB session is.

You should also consider changing this fixture (and most of the other fixtures) to scope='session', so the DB doesn't have to be re-created for each individual test (and so the app doesn't have to be re-instantiated, although that's trivial overhead compared to the DB). But then you have to do some cleanup manually, after individual tests that modify DB records.

Upvotes: 2

Leyo R
Leyo R

Reputation: 723

You need to use the right app context

 def test_create_admin_user(db, testapp):
    with app.app_context():
      password = bcrypt.generate_password_hash('test')
      User.create(
            uid='00000000000000000000',
            email='[email protected]',
            password=password,
            active=1
        )

      user = User.query.filter_by(email='[email protected]').first()
      assert user.email == '[email protected]'

See https://github.com/Leo-G/Flask-Scaffold/blob/master/scaffold/app/tests.py for a full example

Upvotes: 0

Related Questions