簡體   English   中英

有什么方法可以將參數傳遞給 pytest 夾具?

[英]Any way to pass parameters into pytest fixture?

不是在談論Parameterizing a fixture功能,該功能允許針對硬編碼的一組參數運行多次fixture。

我有很多遵循以下模式的測試:

httpcode = 401  # this is different per call
message = 'some message'  # this is different per call
url = 'some url'  # this is different per call


mock_req = mock.MagicMock(spec_set=urllib2.Request)
with mock.patch('package.module.urllib2.urlopen', autospec=True) as mock_urlopen, \
     mock.patch('package.module.urllib2.Request', autospec=True) as mock_request:
    mock_request.return_value = mock_req
    mock_urlopen.side_effect = urllib2.HTTPError(url, httpcode, message, {}, None)
    connection = MyClass()
    with pytest.raises(MyException):
        connection.some_function()  # this changes

本質上,我有一個 API 客戶端類,它包含自定義的、有意義的異常,這些異常將 urllib2 錯誤包裝在特定於 API 的東西中。 所以,我有這個模式——修補一些方法,並在其中一個上設置副作用。 我可能在十幾個不同的測試中使用它,唯一的區別是在 side_effect 中使用的三個變量,以及我調用的 MyClass() 方法。

有沒有辦法讓它成為一個 pytest 夾具並傳入這些變量?

您可以使用間接夾具參數化http://pytest.org/latest/example/parametrize.html#deferring-the-setup-of-parametrized-resources

@pytest.fixture()
def your_fixture(request):
    httpcode, message, url = request.param
    mock_req = mock.MagicMock(spec_set=urllib2.Request)
    with mock.patch('package.module.urllib2.urlopen', autospec=True) as mock_urlopen, \
         mock.patch('package.module.urllib2.Request', autospec=True) as mock_request:
        mock_request.return_value = mock_req
        mock_urlopen.side_effect = urllib2.HTTPError(url, httpcode, message, {}, None)
        connection = MyClass()
        with pytest.raises(MyException):
            connection.some_function()  # this changes


@pytest.mark.parametrize('your_fixture', [
    (403, 'some message', 'some url')
], indirect=True)
def test(your_fixture):
   ...

並且 your_fixture 將在使用所需參數進行測試之前運行

自從發布我的問題以來,我已經對此進行了更多研究,我能想到的最好的方法是:

固定裝置不能以這種方式工作。 只需使用常規功能,即:

def my_fixture(httpcode, message, url):
    mock_req = mock.MagicMock(spec_set=urllib2.Request)
    with mock.patch('package.module.urllib2.urlopen', autospec=True) as mock_urlopen, \
         mock.patch('package.module.urllib2.Request', autospec=True) as mock_request:
        mock_request.return_value = mock_req
        mock_urlopen.side_effect = urllib2.HTTPError(url, httpcode, message, {}, None)
        connection = MyClass()
        return (connection, mock_request, mock_urlopen)

def test_something():
    connection, mock_req, mock_urlopen = my_fixture(401, 'some message', 'some url')
    with pytest.raises(MyException):
        connection.some_function()  # this changes

如何將參數傳遞給夾具?

暫時解開這個想法:你要求一個夾具,它是一個函數,它對參數做出反應。 因此,返回一個對參數做出反應的函數:

@pytest.fixture
def get_named_service():
    def _get_named_service(name):
        result = do_something_with_name(name)
        return result
    return _get_named_service

因此,在測試中,您可以為函數提供參數:

def test_stuff(get_named_service):
    awesome_service = get_named_service('awesome')
    terrible_service = get_named_service('terrible')
    # Now you can do stuff with both services.

這被記錄為工廠模式:
https://docs.pytest.org/en/latest/how-to/fixtures.html#factories-as-fixtures

正如 OP 所發現的,這只是一個函數,但其​​優點是位於所有其他常見實用程序和設置/拆卸代碼所在的conftest中; 加上自我記錄測試的依賴關系。

pytest.mark 的一些技巧,我們有一個帶參數的夾具。

from allure import attach
from pytest import fixture, mark


def get_precondition_params(request_fixture, fixture_function_name: str):
    precondition_params = request_fixture.keywords.get("preconditions_params")
    result = precondition_params.args[0].pop(fixture_function_name) if precondition_params is not None else None
    return result


@fixture(scope="function")
def setup_fixture_1(request):
    params = get_precondition_params(request, "setup_fixture_1")
    return params


@mark.preconditions_params(
    {
        "setup_fixture_1": {
            "param_1": "param_1 value for setup_fixture_1",
            "param_2": "param_2 value for setup_fixture_1"
        },
    }
)
def test_function(setup_fixture_1):
    attach(str(setup_fixture_1), "setup_fixture_1 value")

現在我們可以使用一個夾具代碼,用標記對其進行參數化,並使用夾具內的參數做任何事情。 並且夾具將作為前提條件(必須如何)執行,而不是作為步驟(就像我們從夾具返回函數一樣)。

我知道這已經過時了,但也許它可以幫助那些再次遇到這個問題的人

@pytest.fixture
def data_patcher(request):

    def get_output_test_data(filename, as_of_date=None):
         # a bunch of stuff to configure output
        return output

    def teardown():
        pass

    request.addfinalizer(teardown)

    return get_output_test_data

然后,在函數內部:

with patch('function to patch', new=data_patcher):

暫無
暫無

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

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