简体   繁体   中英

Flask unit testing - How to reset app.url_map for each test?

I'm writing a series of unit tests for a Flask app. The setup for each test is as follows:

  • Create a Flask app in testing mode ( app.testing = True ).
  • Mount a test endpoint (route) on a blueprint within the test app.
  • (Then, exercise some tests on the endpoint...)

The problem is that the app instance used in my tests accumulates the routes added from the previous tests instead of starting from a clean slate. It's as if app.url_map is never reset even though I create a new app each time...

Here's the code of my setup function, which runs before each test (I am using pytest):

def setup(flask_app):
    app = flask_app

    # Mount a test endpoint on the API blueprint.
    bp = app.blueprints["api"]
    bp.add_url_rule('/foo', view_func=test_view, methods=['GET', ])

    print(app.url_map)

flask_app is a pytest fixture that creates a new test app, something like this:

@pytest.fixture()
def flask_app():
    from my_app import create_app
    app = create_app('testing')
    # Configure a bunch of things on app...
    return app

If I write three tests, my setup function is called three times and logs the following for app.url_map :

# 1st test — My new '/api/foo' rule doesn't even show yet...
# For that, I'd need to re-register the blueprint after adding the URL to it.

Map([<Rule '/' (HEAD, OPTIONS, GET) -> main.index>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>])


# 2nd test — Rule '/api/foo' added once

Map([<Rule '/' (HEAD, OPTIONS, GET) -> main.index>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/api/foo' (HEAD, OPTIONS, GET) -> api.test_view>])


# 3rd test — Rule '/api/foo' added twice

Map([<Rule '/' (HEAD, OPTIONS, GET) -> main.index>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/api/foo' (HEAD, OPTIONS, GET) -> api.test_view>],
<Rule '/api/foo' (HEAD, OPTIONS, GET) -> api.test_view>]

In my actual code (a bit more complicated), I get the following error:

AssertionError: View function mapping is overwriting an existing endpoint function:
lib/flask/app.py:1068: AssertionError

Which makes sense, since I'm trying to add the same view multiple times... Why don't I get a fresh app instance every time I run a new test?

I'm not even sure if this is Flask issue or a pytest issue... :(

I could solve a similar problem by moving all stuff you instantiate for the setup into the setup (even the import of the libraries you are using there). Of course, this can be done in a more elegant way by having a create_app() method like you do for your whole flask application. The important point to take away here is to take the instance that keeps the state (here the endpoints) out of the global scope and move it into the create_app() method.

Tell me if you need more information on this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM