Error in tests with python 3.7, pytest and flask Blueprint

Asked

Viewed 154 times

0

I’m starting a very basic Flask application for learning purposes. The apps are running normally. The problem is testing with pytest.

I am using in pipenv: python 3.7.2, Flask==1.0.2, pytest-flask==0.14.0 and pytest=4.3.0

project structure.

├── setup.py ├── manager.py ├── tests │ ├── test_root.py │ ├── conftest.py │ └── pytest.ini └── app ├── __init__.py └── main.py


manager.py

import click
from app import app

@click.group()
def order():
    """To use command line."""
    ...

@order.command()
def runserver():
    """To run a server: runserver."""
    app.run(debug=True)

app/main.py

from flask import Blueprint

main_bp = Blueprint('main', __name__)

@main_bp.route("/", methods=["GET"])
def root():
    """Root page."""
    return "<h1> Home Page </h1>"

app/__init__.py

from flask import Flask
from .main import main_bp    

def create_app():
    """Create app and config blueprint."""
    app = Flask(__name__)

    app.register_blueprint(main_bp, url_prefix='/')

    return app    

app = create_app()

app/test/pytest.ini

[vazio]

app/test/conftest.py

import pytest
from app import create_app

@pytest.fixture
def client():
    """Client fixture config."""
    return create_app().test_client()

app/test/test_root.py

import pytest
from flask import Flask, url_for
from app import app

def test_root_should_return_200(client):
    """Test root page."""
    assert client.get('/').status_code == 200

def test_about_should_return_200(client):
    """Test about page."""
    assert client.get(url_for('main.about', external=True)).status_code == 200

When I use assert client.get('/').status_code == 200 the test passes normal mind.

When I use the url_for the test does not pass assert client.get(url_for('main.about', external=True)).status_code

and I have the following mistake:


tests/test_root.py::test_root_should_return_200 PASSED                                                                      [ 50%]
tests/test_root.py::test_about_should_return_200 FAILED                                                                     [100%]

========================================= FAILURES =================================
_____________________________ test_about_should_return_200 ____________
endpoint = 'main.about', values = {'external': True}, appctx = None, reqctx = None

    def url_for(endpoint, **values):
        """Generates a URL to the given endpoint with the method provided.

        Variable arguments that are unknown to the target endpoint are appended
        to the generated URL as query arguments.  If the value of a query argument
        is ``None``, the whole pair is skipped.  In case blueprints are active
        you can shortcut references to the same blueprint by prefixing the
        local endpoint with a dot (``.``).

...

E           RuntimeError: Attempted to generate a URL without the application context being pushed. This has to be executed when application context is available.

/home/mn/.local/share/virtualenvs/CTRLEstoque-ukt8lCc8/lib/python3.7/site-packages/flask/helpers.py:294: RuntimeError
=============================================== 1 failed, 1 passed in 0.34 seconds =======================================

Hold on You could help me with this mistake???

1 answer

0


The error says that you are not in the context of the application when trying to generate the URL with the function url_for. In the fixture creation file on conftest.py you can instead of returning the client, return the application. Then it would look like this:

import pytest
from app import create_app

@pytest.fixture
def app():
    """Client fixture config."""
    return create_app()

Once done, your test will then be as follows:

import pytest
from flask import Flask, url_for
from app import app

def test_root_should_return_200(app):
    """Test root page."""
    assert app.test_client().get('/').status_code == 200

def test_about_should_return_200(app):
    """Test about page."""
    app.app_context().push()
    assert app.test_client().get(url_for('main.about', external=True)).status_code == 200

app.app_context().push() push the context of the application. This way, you will be within the context of the application when you assert.

  • 1

    Thank you Igor, I understood clearly now, I still have a lot to study to improve... Thank you.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.