簡體   English   中英

pytest:以 DRY 方式參數化夾具

[英]pytest: parameterize fixtures in a DRY way

使用 Pytest 夾具,我正在尋找一種將設置覆蓋傳遞給我的應用程序夾具的方法,因此我可以測試不同的設置而無需定義不同的夾具。

在為 Flask 創建測試時,我使用一種通用模式來初始化應用程序和數據庫,如下所示。 請注意, db固定裝置將app固定裝置硬編碼為參數。

from myapp import create_app

@pytest.fixture
def app():
    settings_override = {}  # By setting values here, I can pass in different Flask config variables
    app = create_app(settings_override)
    return app

@pytest.fixture
def db(app):
    do_something_to_create_the_database(app)  # app needed for context
    yield db

然后,許多測試可能會使用上面定義的固定裝置,例如。

def test_my_application_1(db, app):
  ...

def test_my_application_2(db, app):
  ...

假設我想用不同的設置初始化應用程序夾具,假設我可以將這些設置傳遞給上面定義的 create_app() function。 在每個測試的基礎上,如何附加appdb裝置,以便我可以將設置覆蓋傳遞給app裝置? 有沒有辦法可以在測試用例級別參數化夾具,以便我可以將不同的設置傳遞給夾具?

IE

# for this test, I want to pass the BAZ=True setting to the app fixture. 
def test_my_application_1(db, app):
  ...

# for this test, I want to pass FOO=BAR setting to the app fixture
def test_my_application_2(db, app):
  ...

我很感激你提供的任何建議。

更新:來自@mrbean-bremen 的解決方案

感謝@MrBean Bremen 提供優雅的解決方案。 通過使用 hasattr 稍作修改,我能夠擴展解決方案以接受參數覆蓋或接受默認值。

@pytest.fixture(scope='function')
def app(request):
    settings_override = {
        'SQLALCHEMY_DATABASE_URI': "sqlite:///:memory:",
    }
    params = request.param if hasattr(request, 'param') else {}
    return create_app({**settings_override, **params})


@pytest.fixture(scope='function')
def db(app):
    with app.app_context():
       ....


def test_without_params(db, app):
    ...


@pytest.mark.parametrize("app", [{'DEBUG': True}], indirect=True)
def test_with_overrides(db, app):
    ...


您可以嘗試將設置作為字典參數傳遞給夾具,如下所示:

import pytest
from myapp import create_app

@pytest.fixture
def app(request):
    settings_override = {
        'SQLALCHEMY_DATABASE_URI': "sqlite:///:memory:",
    }
    params = request.param if hasattr(request, 'param') else {}
    return create_app({**settings_override, **params})

@pytest.fixture
def db(app):
    do_something_to_create_the_database(app)
    yield db

def test_my_application_no_override_params(db, app):
    ...

@pytest.mark.parametrize("app", [{'BAZ': True}], indirect=True)
def test_my_application_1(db, app):
    ...

@pytest.mark.parametrize("app", [{'FOO': 'BAR'}], indirect=True)
def test_my_application_2(db, app):
    ...

request object 使夾具能夠訪問請求的測試上下文,並且可以用作任何夾具中的參數。
pytest.mark.parametrize裝飾器中的indirect=True參數將參數傳遞給request object 的可選param屬性,因此這實質上是對夾具本身進行參數化。

更新:
我添加了@JoeJ 提出的有用的添加(使用hasattr ),這使得可以在沒有其他參數的情況下使用測試。

暫無
暫無

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

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