目錄:
- 安裝及入門
- 使用和調(diào)用方法
- 原有TestSuite使用方法
- 斷言的編寫和報(bào)告
- Pytest fixtures:清晰 模塊化 易擴(kuò)展
- 使用Marks標(biāo)記測(cè)試用例
- Monkeypatching/對(duì)模塊和環(huán)境進(jìn)行Mock
- 使用tmp目錄和文件
- 捕獲stdout及stderr輸出
- 捕獲警告信息
- 模塊及測(cè)試文件中集成doctest測(cè)試
- skip及xfail: 處理不能成功的測(cè)試用例
- Fixture方法及測(cè)試用例的參數(shù)化
- 緩存: 使用跨執(zhí)行狀態(tài)
- unittest.TestCase支持
- 運(yùn)行Nose用例
- 經(jīng)典xUnit風(fēng)格的setup/teardown
- 安裝和使用插件
- 插件編寫
- 編寫鉤子(hook)方法
- 運(yùn)行日志
- API參考
- 優(yōu)質(zhì)集成實(shí)踐
- 片狀測(cè)試
- Pytest導(dǎo)入機(jī)制及sys.path/PYTHONPATH
- 配置選項(xiàng)
- 示例及自定義技巧
- Bash自動(dòng)補(bǔ)全設(shè)置
斷言的編寫和報(bào)告
使用assert語(yǔ)句進(jìn)行斷言
pytest允許你使用標(biāo)準(zhǔn)的Pythonassert
斷言語(yǔ)句來(lái)驗(yàn)證測(cè)試中的期望結(jié)果和實(shí)際結(jié)果。 例如悔捶,你可以編寫以下內(nèi)容:
# test_assert1.py文件內(nèi)容
def f():
return 3
def test_function():
assert f() == 4
來(lái)斷言你的函數(shù)返回一個(gè)特定的值铃慷。 如果此斷言失敗,你將看到函數(shù)調(diào)用的返回值:
$ pytest test_assert1.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 item
test_assert1.py F [100%]
================================= FAILURES =================================
______________________________ test_function _______________________________
def test_function():
> assert f() == 4
E assert 3 == 4
E + where 3 = f()
test_assert1.py:5: AssertionError
========================= 1 failed in 0.12 seconds =========================
pytest
支持顯示常見(jiàn)的包括調(diào)用蜕该,屬性犁柜,比較以及二元和一元運(yùn)算符子表達(dá)式的值 (參考:pytest執(zhí)行Python測(cè)試失敗報(bào)告示例)。 你可以在不使用繁瑣的Python慣用構(gòu)造樣板代碼的同時(shí)堂淡,不丟失斷言失敗的對(duì)比信息(內(nèi)省信息)馋缅。
當(dāng)然,你也可以像下面所示绢淀,指定斷言失敗的返回消息:
assert a % 2 == 0, "值為奇數(shù)萤悴,應(yīng)為偶數(shù)"
這樣將不會(huì)斷言失敗對(duì)比信息(內(nèi)省信息),而只簡(jiǎn)單地在追溯信息中顯示你指定的失敗返回信息皆的。
有關(guān)斷言內(nèi)省的更多信息覆履,請(qǐng)參閱高級(jí)斷言內(nèi)省。
異常斷言
你可以像如下所示费薄,使用pytest.raises
作為上下文管理器來(lái)進(jìn)行異常斷言:
import pytest
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
如果需要訪問(wèn)實(shí)際的異常信息内狗,你可以使用:
def test_recursion_depth():
with pytest.raises(RuntimeError) as excinfo:
def f():
f()
f()
assert 'maximum recursion' in str(excinfo.value)
excinfo
是一個(gè)ExceptionInfo
實(shí)例,它是實(shí)際異常的裝飾器义锥。 其主要屬性有.type
柳沙,.value
及.traceback
三種
版本3.0已修改
在上下文管理器中,你可以使用參數(shù)message
來(lái)指定自定義失敗信息:
>>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"):
... pass
... Failed: Expecting ZeroDivisionError
如果你想編寫適用于Python 2.4的測(cè)試代碼拌倍,你還可以使用其他兩種方法來(lái)測(cè)試預(yù)期的異常:
pytest.raises(ExpectedException, func, *args, **kwargs)
pytest.raises(ExpectedException, "func(*args, **kwargs)")
兩者都可以對(duì)帶任意參數(shù)的函數(shù)赂鲤,斷言是否出現(xiàn)了期望的異常:ExpectedException
噪径。 即使沒(méi)有異常或出現(xiàn)了不同的異常数初,報(bào)告生成器也能輸出一些有用的斷言信息找爱。
注意,也可以為pytest.mark.xfail
指定一個(gè)“raises”參數(shù)泡孩,當(dāng)引發(fā)異常時(shí)標(biāo)記用例失敵瞪恪:
@pytest.mark.xfail(raises=IndexError)
def test_f():
f()
對(duì)于你在代碼中故意設(shè)置的異常,使用pytest.raises
斷言更加好用仑鸥,而將@ pytest.mark.xfail
與check函數(shù)一起使用對(duì)于已知未修復(fù)或依賴中的bug會(huì)更好吮播。
此外,上下文管理器表單接受match
關(guān)鍵字參數(shù)來(lái)測(cè)試正則表達(dá)式匹配中的異常(如unittest
中的TestCase.assertRaisesRegexp
方法):
import pytest
def myfunc():
raise ValueError("Exception 123 raised")
def test_match():
with pytest.raises(ValueError, match=r'.* 123 .*'):
myfunc()
match
變量后的正則表達(dá)式與使用re.search
函數(shù)來(lái)進(jìn)行匹配一致眼俊。 因此在上面的例子中意狠,match ='123'
不會(huì)引發(fā)異常。
警示斷言
2.8版本新增
你可以使用pytest.warns
檢查代碼是否引發(fā)了特定警告疮胖。
使用上下文對(duì)比
2.0版本新增
pytest
可以在斷言的比較中提供豐富的上下文信息环戈。 例如:
# test_assert2.py文件內(nèi)容
def test_set_comparison():
set1 = set("1308")
set2 = set("8035")
assert set1 == set2
當(dāng)你運(yùn)行這個(gè)模塊后
$ pytest test_assert2.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 item
test_assert2.py F [100%]
================================= FAILURES =================================
___________________________ test_set_comparison ____________________________
def test_set_comparison():
set1 = set("1308")
set2 = set("8035")
> assert set1 == set2
E AssertionError: assert {'0', '1', '3', '8'} == {'0', '3', '5', '8'}
E Extra items in the left set:
E '1'
E Extra items in the right set:
E '5'
E Use -v to get the full diff
test_assert2.py:5: AssertionError
========================= 1 failed in 0.12 seconds =========================
對(duì)大量用例進(jìn)行了特定對(duì)比:
- 長(zhǎng)字符串?dāng)嘌裕猴@示上下文差異
- 長(zhǎng)序列斷言:顯示第一個(gè)失敗的索引
- 字典斷言:顯示不同的key-value對(duì)
有關(guān)更多示例,請(qǐng)參閱報(bào)告樣例澎灸。
自定義斷言對(duì)比信息
可以通過(guò)實(shí)現(xiàn)hook
方法pytest_assertrepr_compare
來(lái)在斷言結(jié)果中添加你自己的詳細(xì)說(shuō)明信息院塞。
pytest_assertrepr_compare(config, op, left, right) [源碼]
返回失敗斷言表達(dá)式中的對(duì)比信息。
如果沒(méi)有自定義對(duì)比信息性昭,則返回None迫悠,否則返回一列字符串。 字符串將由換行符連接巩梢,但字符串中的任何換行符都將被轉(zhuǎn)義创泄。 請(qǐng)注意,除第一行外的所有行都將略微縮進(jìn)括蝠,目的是將第一行作為摘要鞠抑。
參數(shù): config(pytest.config.Config* - pytest config 對(duì)象
例如,在conftest.py文件中添加以下鉤子方法忌警,可以為Foo
對(duì)象提供了附加對(duì)比信息:
# conftest.py內(nèi)容
from test_foocompare import Foo
def pytest_assertrepr_compare(op, left, right):
if isinstance(left, Foo) and isinstance(right, Foo) and op == "==":
return ['Foo實(shí)例對(duì)比:',
' 值: %s != %s' % (left.val, right.val)]
現(xiàn)在搁拙,在測(cè)試模塊使用
# test_foocompare.py內(nèi)容
class Foo(object):
def __init__(self, val):
self.val = val
def __eq__(self, other):
return self.val == other.val
def test_compare():
f1 = Foo(1)
f2 = Foo(2)
assert f1 == f2
運(yùn)行這個(gè)測(cè)試模塊你可以看到conftest.py
文件中定義的自定義輸出:
$ pytest -q test_foocompare.py
F [100%]
================================= FAILURES =================================
_______________________________ test_compare _______________________________
def test_compare():
f1 = Foo(1)
f2 = Foo(2)
> assert f1 == f2
E assert Foo實(shí)例對(duì)比:
E 值: 1 != 2
test_foocompare.py:11: AssertionError
1 failed in 0.12 seconds
高級(jí)斷言內(nèi)省
2.1版本新功能
報(bào)告有關(guān)失敗斷言的詳細(xì)信息是通過(guò)在運(yùn)行之前重寫assert語(yǔ)句來(lái)實(shí)現(xiàn)的。 重寫的斷言語(yǔ)句將內(nèi)省信息放入斷言失敗消息中法绵。 pytest
只重寫測(cè)試收集過(guò)程直接發(fā)現(xiàn)的測(cè)試模塊中的assert斷言箕速,因此在支持模塊(非測(cè)試模塊)中的斷言,不會(huì)被重寫朋譬。
你可以在導(dǎo)入模塊前通過(guò)調(diào)用register_assert_rewrite
手動(dòng)啟用斷言重寫(比如可以在conftest.py
這樣使用)盐茎。
注意
pytest
通過(guò)使用導(dǎo)入hook方法寫入新的pyc
文件來(lái)重寫測(cè)試模塊。 通常這種結(jié)構(gòu)比較清晰徙赢。 但是字柠,如果你混亂導(dǎo)入探越,導(dǎo)入的hook方法可能會(huì)受到干擾。
如果是這種情況窑业,您有兩種選擇:
通過(guò)將字符串PYTEST_DONT_REWRITE
添加到其docstring來(lái)禁用特定模塊的重寫钦幔。
使用--assert = plain
禁用所有模塊的重寫。
此外常柄,如果無(wú)法寫入新的.pyc
文件(如在只讀文件系統(tǒng)或zip文件中)鲤氢,重寫將無(wú)提示失敗。
有關(guān)進(jìn)一步的信息西潘,課參閱:本杰明彼得森寫的pytest的新斷言改寫的幕后故事卷玉。
版本2.1新功能:添加斷言重寫作為備用內(nèi)省技術(shù)。
版本2.1更改:引入--assert
選項(xiàng)秸架。 棄用--no-assert
和--nomagic
揍庄。
版本3.0版更改:刪除--no-assert
和--nomagic選項(xiàng)咆蒿。 刪除
--assert = reinterp`選項(xiàng)东抹。