簡體   English   中英

如何在pytest中完成每次測試后完全拆解燒瓶應用程序?

[英]How to Completely Teardown Flask App After Each Test in pytest?

我正在使用Pytest測試我的Flask應用程序。 我有3個文件

tests/
--conftest.py
--test_one.py
--test_two.py

如果我使用以下命令運行test_one.py test_two.py ,它將正常工作。

python -m pytest tests/test_one.py

當我嘗試使用以下命令運行所有測試時出現問題:

python -m pytest tests

我收到此錯誤:

AssertionError: View function mapping is overwriting an existing endpoint function: serve_static

我真的不會對這個錯誤感到驚訝,因為init_app(app)被調用兩次(每個文件一次),我不會拆除實際的app

我的問題是, 有沒有辦法徹底拆除燒瓶應用程序並為每個單獨的測試重建它? 我正在尋找拆除的實際命令(即app.teardown()

編輯:我願意接受設置Flask應用測試環境的其他方法,如果能解決這個問題(不創建新問題)。

編輯2:我發現了這個問題。 它是類似的,可以解決我的問題,但它涉及導入函數內部。 我懷疑必須有更好的方法。

conftest.py

import os
import pytest

from app import app, init_app
from config import TestConfig


@pytest.fixture(scope='function')
def client():

    app.config.from_object(TestConfig)

    with app.test_client() as client:
        with app.app_context():
            init_app(app)
        yield client

    try:
        os.remove('tests/testing.db')
    except FileNotFoundError:
        pass

應用程序/ __ init__.py

app = Flask(__name__)
app.url_map._rules.clear()
db = SQLAlchemy(app)
migrate = Migrate(app, db)

def init_app(app):
    ...

我會在每個繼承TestCase的文件中創建一個Class。 這樣,您可以使用函數setup()在每次測試之前將testclient生成為Instance-Variable。 這樣,您可以確保每個測試都具有相同的環境。

from unittest import TestCase
from app import app as application

class TestApplication(TestCase):
  def setUp(self):
    self.client = application.app.test_client()

  def test_sth(self):
    r = self.client.get('/approute2sth')
    self.assertEqual(r.status_code, 200)

  def test_sth_else(self):
    r = self.client.get('/approute2sth_else')
    self.assertEqual(r.status_code, 200)

我正在考慮一個解決方案,但不涉及拆除燒瓶應用程序。 我不喜歡為每個測試用例拆掉它,因為這本身會導致每個測試用例的正常運行時間增加(除非燒瓶應用初始化對於每個測試用例都是唯一的)

由於測試在pytest中並行運行,因此您可以執行以下操作

try:
    app
except NameError:
    app.config.from_object(TestConfig)
    with app.test_client() as client:
        with app.app_context():
            init_app(app)
else:
    print("App is already configured. Let us proceed with the test case")

您可以將它包裝在單個類中,而不是采用上述方法

以下某些組合可能有效。 我相信這是做舊的方式(盡管我自己從未做過)。 我的印象是pytest使用燈具的概念來直接teardown()

#clear current db session
db.session.remove()
#drop all tables in db
db.drop_all()
#remove app_context
app.app_context.pop()

有關更多討論,請參閱pytest上的此博客文章

最終我的問題是我如何創建我的app 由於它是在__init__.py創建的一個gloval變量,因此我無法為每次測試重新制作它。 我重構了__init__.py (以及我的其余代碼)以使用create_app函數,我可以一遍又一遍地創建相同的應用程序。 以下代碼最終正常運行。

應用程序/ __ init__.py

def create_app(config)
    app = Flask(__name__)
    app.url_map._rules.clear()
    from .models import db
    app.config.from_object(config)
    with app.app_context():

    return app

def init_app(app):
    ...

conftest.py

import os
import pytest

from app import create_app, init_app
from config import TestConfig


@pytest.fixture(scope='function')
def client():
    app = create_app()
    app.config.from_object(TestConfig)

    with app.test_client() as client:
        with app.app_context():
            from app.models import db
            init_app(app, db)
            yield client

    try:
        os.remove('tests/testing.db')
    except FileNotFoundError:
        pass

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM