1. 程式人生 > 其它 >Pytest學習(二)

Pytest學習(二)

第一次(或n次)故障後停止

在第一(n)次失敗後停止測試過程:

pytest -x           # stop after first failure
pytest --maxfail=2  # stop after two failures

指定測試/選擇測試

pytest支援幾種方法來執行和從命令列中選擇測試。

在模組中執行測試

pytest test_mod.py

在目錄中執行測試

pytest testing/

按關鍵字表達式執行測試

pytest -k "MyClass and not method"

這將執行包含與給定名稱匹配的名稱的測試字串表示式

(不區分大小寫),它可以包括使用檔名、類名和函式名作為變數的Python運算子。上面的例子將執行TestMyClass.test_something但不是TestMyClass.test_method_simple.

標記函式

Pytest 查詢測試策略

預設情況下,pytest 會遞迴查詢當前目錄下所有以test開始或結尾的 Python 指令碼,並執行檔案內的所有以test開始或結束的函式和方法。

對於下面指令碼:

# test_no_mark.py

def test_func1():
    assert 1 == 1

def test_func2():
    assert 1 != 1

直接執行測試指令碼會同時執行所有測試函式:

$ pytest tests/test-function/test_no_mark.py
============================= test session starts =============================
platform win32 -- Python 3.6.4, pytest-3.6.1, py-1.5.2, pluggy-0.6.0
rootdir: F:\self-repo\learning-pytest, inifile:
collected 2 items

tests\test-function\test_no_mark.py .F                                   [100%]

================================== FAILURES ===================================
_________________________________ test_func2 __________________________________

    def test_func2():
>       assert 1 != 1
E       assert 1 != 1

tests\test-function\test_no_mark.py:6: AssertionError
===================== 1 failed, 1 passed in 0.07 seconds ======================

標記測試函式

由於某種原因(如test_func2的功能尚未開發完成),我們只想執行指定的測試函式。在 pytest 中有幾種方式可以解決:

第一種,顯式指定函式名,通過::標記。

$ pytest tests/test-function/test_no_mark.py::test_func1
============================= test session starts =============================
platform win32 -- Python 3.6.4, pytest-3.6.1, py-1.5.2, pluggy-0.6.0
rootdir: F:\self-repo\learning-pytest, inifile:
collected 1 item

tests\test-function\test_no_mark.py .                                    [100%]

========================== 1 passed in 0.02 seconds ===========================

第二種,使用模糊匹配,使用-k選項標識。

$ pytest -k func1 tests/test-function/test_no_mark.py
============================= test session starts =============================
platform win32 -- Python 3.6.4, pytest-3.6.1, py-1.5.2, pluggy-0.6.0
rootdir: F:\self-repo\learning-pytest, inifile:
collected 2 items / 1 deselected

tests\test-function\test_no_mark.py .                                    [100%]

=================== 1 passed, 1 deselected in 0.03 seconds ====================

註解

以上兩種方法,第一種一次只能指定一個測試函式,當要進行批量測試時無能為力;第二種方法可以批量操作,但需要所有測試的函式名包含相同的模式,也不方便。

第三種,使用pytest.mark在函式上進行標記。

帶標記的測試函式如:

# test_with_mark.py

@pytest.mark.finished
def test_func1():
    assert 1 == 1

@pytest.mark.unfinished
def test_func2():
    assert 1 != 1

測試時使用-m選擇標記的測試函式:

$ pytest -m finished tests/test-function/test_with_mark.py
============================= test session starts =============================
platform win32 -- Python 3.6.4, pytest-3.6.1, py-1.5.2, pluggy-0.6.0
rootdir: F:\self-repo\learning-pytest, inifile:
collected 2 items / 1 deselected

tests\test-function\test_with_mark.py .                                  [100%]

=================== 1 passed, 1 deselected in 0.10 seconds ====================

使用 mark,我們可以給每個函式打上不同的標記,測試時指定就可以允許所有被標記的函式。

註解

一個函式可以打多個標記;多個函式也可以打相同的標記。

執行測試時使用-m選項可以加上邏輯,如:

$ pytest -m "finished and commit"

$ pytest -m "finished and not merged"

跳過測試

上一節提到 pytest 使用標記過濾測試函式,所以對於那些尚未開發完成的測試,最好的處理方式就是略過而不執行測試。

按正向的思路,我們只要通過標記指定要測試的就可以解決這個問題;但有時候的處境是我們能進行反向的操作才是最好的解決途徑,即通過標記指定要跳過的測試。

Pytest 使用特定的標記pytest.mark.skip完美的解決了這個問題。

# test_skip.py

@pytest.mark.skip(reason='out-of-date api')
def test_connect():
    pass

執行結果可以看到該測試已被忽略:

$ pytest tests/test-function/test_skip.py
============================= test session starts =============================
platform win32 -- Python 3.6.4, pytest-3.6.1, py-1.5.2, pluggy-0.6.0
rootdir: F:\self-repo\learning-pytest, inifile:
collected 1 item

tests\test-function\test_skip.py s                                       [100%]

========================== 1 skipped in 0.13 seconds ==========================

註解

pytest 使用s表示測試被跳過(SKIPPED)。

Pytest 還支援使用pytest.mark.skipif為測試函式指定被忽略的條件。

@pytest.mark.skipif(conn.__version__ < '0.2.0',
                    reason='not supported until v0.2.0')
def test_api():
    pass


以前-好記性不如爛筆頭 現在-好記性不如爛鍵盤