Pytest權威教程13-Fixture方法及測試用例的參數化


返回: Pytest權威教程

Fixture方法及測試用例的參數化

Pytest在多個級別啟用測試參數化:

  • pytest.fixture()允許一個[參數化Fixture方法。
  • @pytest.mark.parametrize允許在測試函數或類中定義多組參數和Fixture。
  • pytest_generate_tests允許用戶定義自定義參數化方案或擴展。

@pytest.mark.parametrize:參數化測試函數

2.2版中的新函數。

版本2.4中的更改:一些改進。

內置的pytest.mark.parametrize裝飾器支持測試函數的參數化。以下是測試函數的示例,該函數實現檢查某個輸入是否導致預期輸出:

# content of test_expectation.py
import pytest

@pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+4",6),("6*9",42)])
def test_eval(test_input,expected):
    assert eval(test_input) == expected

這里,@parametrize裝飾器定義了三個不同的參數,test_input,expected組成元組,以便test_eval函數依次使用它們運行三次:

$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y,pytest-4.x.y,py-1.x.y,pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 3 items

test_expectation.py ..F                                              [100%]

================================= FAILURES =================================
____________________________ test_eval[6*9-42] _____________________________

test_input = '6*9',expected = 42

 @pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+4",6),("6*9",42)])
 def test_eval(test_input,expected):
>       assert eval(test_input) == expected
E       AssertionError: assert 54 == 42
E        +  where 54 = eval('6*9')

test_expectation.py:6: AssertionError
==================== 1 failed,2 passed in 0.12 seconds ====================

注意: 默認情況下,pytest會轉義unicode字符串中用於參數化的任何非ascii字符,因為它有幾個缺點。但是,如果你想在參數化中使用unicode字符串並在終端中按原樣(非轉義)查看它們,請在以下位置使用此選項pytest.ini
(譯者注:需要pytest>=5.0.0, 數據或ids中的中文才能正常顯示)

[pytest]
disable_test_id_escaping_and_forfeit_all_rights_to_community_support = True

但請記住,這可能會導致不必要的副作用甚至是錯誤,具體取決於所使用的操作系統和當前安裝的插件,因此使用它需要你自擔風險。

如本例所示,只有一對輸入/輸出值無法通過簡單的測試用例。和通常的測試函數參數一樣,你可以在traceback中看到inputoutput值。

請注意,你還可以在類或模塊上使用參數化標記(請參閱[使用屬性標記測試函數),這將使用參數集調用多個函數。

也可以在參數化中標記單個測試實例,例如使用內置mark.xfail

# content of test_expectation.py
import pytest

@pytest.mark.parametrize(
    "test_input,expected",
    [("3+5",8),("2+4",6),pytest.param("6*9",42,marks=pytest.mark.xfail)],
)
def test_eval(test_input,expected):
    assert eval(test_input) == expected

我們運行這個:

$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y,pytest-4.x.y,py-1.x.y,pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 3 items

test_expectation.py ..x                                              [100%]

=================== 2 passed,1 xfailed in 0.12 seconds ====================

之前導致失敗的一個參數集現在顯示為“xfailed(預期失敗)”測試。

如果提供的值parametrize導致空列表 - 例如,如果它們是由某個函數動態生成的 - 則pytest的行為由該empty_parameter_set_mark選項定義。

要獲得多個參數化參數的所有組合,你可以堆疊parametrize裝飾器:

import pytest

@pytest.mark.parametrize("x",[0,1])
@pytest.mark.parametrize("y",[2,3])
def test_foo(x,y):
    pass

這將運行與設定參數的測試x=0/y=2,x=1/y=2,x=0/y=3,並x=1/y=3在裝飾的秩序排氣參數。

基本的pytest_generate_tests例子

有時你可能希望實現自己的參數化方案或實現一些動力來確定Fixture的參數或范圍。為此,你可以使用pytest_generate_tests在收集測試函數時調用的鈎子。通過傳入的metafunc對象,你可以檢查請求的測試上下文,最重要的是,你可以調用metafunc.parametrize()以引起參數化。

例如,假設我們想要運行一個測試,我們想通過一個新的pytest命令行選項設置字符串輸入。讓我們首先編寫一個接受stringinputfixture函數參數的簡單測試:

# content of test_strings.py

def test_valid_string(stringinput):
    assert stringinput.isalpha()

現在我們添加一個conftest.py包含命令行選項和測試函數參數化的文件:

# content of conftest.py

def pytest_addoption(parser):
    parser.addoption(
        "--stringinput",
        action="append",
        default=[],
        help="list of stringinputs to pass to test functions",
    )

def pytest_generate_tests(metafunc):
    if "stringinput" in metafunc.fixturenames:
        metafunc.parametrize("stringinput",metafunc.config.getoption("stringinput"))

如果我們現在傳遞兩個stringinput值,我們的測試將運行兩次:

$ pytest -q --stringinput="hello" --stringinput="world" test_strings.py
..                                                                  [100%]
2 passed in 0.12 seconds

讓我們運行一個stringinput導致測試失敗:

$ pytest -q --stringinput="!" test_strings.py
F                                                                    [100%]
================================= FAILURES =================================
___________________________ test_valid_string[!] ___________________________

stringinput = '!'

 def test_valid_string(stringinput):
>       assert stringinput.isalpha()
E       AssertionError: assert False
E        +  where False = <built-in method isalpha of str object at 0xdeadbeef>()
E        +    where <built-in method isalpha of str object at 0xdeadbeef> = '!'.isalpha

test_strings.py:4: AssertionError
1 failed in 0.12 seconds

正如所料,我們的測試用例失敗。

如果你沒有指定stringinput,它將被跳過,因為metafunc.parametrize()將使用空參數列表調用:

$ pytest -q -rs test_strings.py
s                                                                    [100%]
========================= short test summary info ==========================
SKIPPED [1] test_strings.py: got empty parameter set ['stringinput'],function test_valid_string at $REGENDOC_TMPDIR/test_strings.py:2
1 skipped in 0.12 seconds

注意: metafunc.parametrize使用不同的參數集多次調用時,這些集合中的所有參數名稱都不能重復,否則將引發錯誤。

更多示例

有關更多示例,你可能需要查看更多參數化示例。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM