1. 使用assert聲明
pytest與unittest對比:
pytest | unittest |
---|---|
assert something | assertTrue(something) |
assert a == b | assertEqual(a,b) |
assert a <= b | assertLessEqual(a,b) |
pytest有一個重要的功能,它可以重寫assert關鍵字。pytest會截斷對原生assert的調用,替換爲pytest定義的assert,從而提供更多的失敗信息和細節。
增加一個運行失敗的測試用例:
def test_failure():
"""使用assert"""
t1 = 'a'
t2 = 'b'
assert t1 == t2
運行結果如下:
失敗的測試用例在行首都用一個>號來表示。以E開頭的行是pytest提供的額外判定信息,用於幫助我們瞭解異常的具體情況。
2. 預期異常
定義一個Task類型數據,並增加一個會引起TypeError異常的測試用例:
Task = namedtuple('Task', ['summary', 'owner', 'dine', 'id'])
Task.__new__.__delattr__ = (None, None, False, None)
def test_task():
task = Task();
運行結果如下:
在原本基礎上,增加with pytest.raises(TypeError):
def test_task():
with pytest.raises(TypeError):
task = Task();
再次運行,運行結果如下:
測試用例test_task()中有with pytest.raises(TypeError)聲明,意味着無論with中的內容是什麼,都至少會發生TypeError異常。如果測試通過,說明確實發生來我們預期的TypeError異常;如果測試失敗,說明拋出的是與我們所預期不一致的異常。
另外,可以通過as excinfo語句來獲取異常消息的值。
with pytest.raises(TypeError) as excinfo:
3. 測試函數的標記
pytest提供了標記機制,允許你使用marker對測試函數做標記。一個測試函數可以有多個marker,一個marker也可以用勒標記多個測試函數。
例如,爲了吧選定的測試用例加入冒煙測試,可以對它們添加統一的標識,如:@pytest.mark.smoke。
運行時,通過參數-m來指定:
pytest -m smoke
ps:-m具體用法可查看:《pytest測試實戰》筆記:一
另外,帶有相同標記的測試用例即使存放在不同文件下,也會被一起執行。
4. 跳過測試
pytest自身內置了一些標記:skip、skipif、xfail。
skip、skipif允許你跳過不希望運行的測試。
要跳過某個測試用例,只需簡單地在測試函數上添加@pytest.mark.skip()裝飾器即可。
實際上,可以給到跳過的測試用例添加理由和條件,比如希望它只在包版本低於0.2.0時才生效,應用skipif替代skip:
@pytest.mark.skipif(tasks.__version__ < 0.2.0,
reason = 'not supported until version 0.2.0')
skipif()的判斷條件可以是任何Python表達式。
運行時可以通過-rs查看跳過的原因:
5. 標記預期會失敗的測試
使用skip、skipif標記,測試用例會被直接跳過,不會被執行。使用xfail標記,告訴pytest執行此測試用例,但預期會失敗。
添加兩個測試用例,均使用了xfail來標記,區別在於demo1的assert爲false,demo2的assert爲true:
@pytest.mark.xfail()
def test_demo1():
t1 = 'a'
t2 = 'b'
assert t1 == t2
@pytest.mark.xfail()
def test_demo2():
t1 = 'a'
t2 = 'b'
assert t1 != t2
運行結果如下:
x:XFAIL,expected to fail,預期失敗,實際上也失敗了
X:XPASS,expected to fail but passed,預期失敗,但實際運行並沒有失敗
6. 運行測試子集
運行測試子集有很多方式,不但可以選擇運行某個目錄、文件、類中的測試,還可以選擇運行某一個測試用例(可能在文件中,也可能在類中)。
- 單個目錄:以目錄作爲pytest的參數即可。
- 單個測試文件/模塊:運行單個文件裏的全部測試,以路徑名加文件名作爲pytest參數即可。
- 單個測試函數:運行單個測試函數,在文件名後面添加::符號和函數名。
- 單個測試類:運行測試類,在文件名後面添加::符號和類名(與運行單個測試函數類似)。
- 單個測試類中的測試方法:在文件名後面添加::符號和方法名。
7. 參數化測試
可以使用@pytest.mark.parametrize(argnames, argvalues)裝飾器達到批量傳送參數的目的。
testdata_add = [(1, 2, 3), (3.12, 4.12, 7.24), (-100, 200, 100), ("a", "b", "ab"), ("中文1", "中文2", "中文1中文2"), ("space", " ", "space "), ("null", "", "null")]
# 執行時會根據數據的數量執行對應條數的用例
@pytest.mark.parametrize("num1, num2, expect", testdata_add)
def test_add(num1, num2, expect): # 接收的變量名要和parametrize的一致
"""測試加法運算函數"""
result = add(num1, num2)
assert result == expect
運行結果如下:
也可以爲測試類添加parametrize()轉裝飾器,這種情況下,該數據集會被傳遞給該類的所有類方法。
接下來,會在《pytest測試實戰》筆記:三 中介紹如何使用fixture。fixture的作用是將一些非核心測試邏輯,如:測試數據的檢索和生成,從測試函數中分離出來,以便於其他測試函數複用,同時保持這邊邊緣邏輯的一致性。