Pytest官方教程-04-斷言的編寫和報(bào)告

目錄:

  1. 安裝及入門
  2. 使用和調(diào)用方法
  3. 原有TestSuite使用方法
  4. 斷言的編寫和報(bào)告
  5. Pytest fixtures:清晰 模塊化 易擴(kuò)展
  6. 使用Marks標(biāo)記測(cè)試用例
  7. Monkeypatching/對(duì)模塊和環(huán)境進(jìn)行Mock
  8. 使用tmp目錄和文件
  9. 捕獲stdout及stderr輸出
  10. 捕獲警告信息
  11. 模塊及測(cè)試文件中集成doctest測(cè)試
  12. skip及xfail: 處理不能成功的測(cè)試用例
  13. Fixture方法及測(cè)試用例的參數(shù)化
  14. 緩存: 使用跨執(zhí)行狀態(tài)
  15. unittest.TestCase支持
  16. 運(yùn)行Nose用例
  17. 經(jīng)典xUnit風(fēng)格的setup/teardown
  18. 安裝和使用插件
  19. 插件編寫
  20. 編寫鉤子(hook)方法
  21. 運(yùn)行日志
  22. API參考
    1. 方法(Functions)
    2. 標(biāo)記(Marks)
    3. 鉤子(Hooks)
    4. 裝置(Fixtures)
    5. 對(duì)象(Objects)
    6. 特殊變量(Special Variables)
    7. 環(huán)境變量(Environment Variables)
    8. 配置選項(xiàng)(Configuration Options)
  23. 優(yōu)質(zhì)集成實(shí)踐
  24. 片狀測(cè)試
  25. Pytest導(dǎo)入機(jī)制及sys.path/PYTHONPATH
  26. 配置選項(xiàng)
  27. 示例及自定義技巧
  28. 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)东抹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市沃测,隨后出現(xiàn)的幾起案子缭黔,更是在濱河造成了極大的恐慌,老刑警劉巖蒂破,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件馏谨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡附迷,警方通過(guò)查閱死者的電腦和手機(jī)惧互,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)喇伯,“玉大人喊儡,你說(shuō)我怎么就攤上這事〉揪荩” “怎么了艾猜?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)捻悯。 經(jīng)常有香客問(wèn)我匆赃,道長(zhǎng),這世上最難降的妖魔是什么今缚? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任算柳,我火速辦了婚禮,結(jié)果婚禮上姓言,老公的妹妹穿的比我還像新娘埠居。我一直安慰自己查牌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布滥壕。 她就那樣靜靜地躺著纸颜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绎橘。 梳的紋絲不亂的頭發(fā)上胁孙,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音称鳞,去河邊找鬼涮较。 笑死,一個(gè)胖子當(dāng)著我的面吹牛冈止,可吹牛的內(nèi)容都是我干的狂票。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼熙暴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼闺属!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起周霉,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤掂器,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后俱箱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體国瓮,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年狞谱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乃摹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡跟衅,死狀恐怖孵睬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情与斤,我是刑警寧澤肪康,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站撩穿,受9級(jí)特大地震影響磷支,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜食寡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一雾狈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抵皱,春花似錦善榛、人聲如沸辩蛋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)悼院。三九已至,卻和暖如春咒循,著一層夾襖步出監(jiān)牢的瞬間据途,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工叙甸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颖医,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓裆蒸,卻偏偏與公主長(zhǎng)得像熔萧,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子僚祷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容