目錄:
- 安裝及入門
- 使用和調(diào)用方法
- 原有TestSuite使用方法
- 斷言的編寫和報告
- Pytest fixtures:清晰 模塊化 易擴(kuò)展
- 使用Marks標(biāo)記測試用例
- Monkeypatching/對模塊和環(huán)境進(jìn)行Mock
- 使用tmp目錄和文件
- 捕獲stdout及stderr輸出
- 捕獲警告信息
- 模塊及測試文件中集成doctest測試
- skip及xfail: 處理不能成功的測試用例
- Fixture方法及測試用例的參數(shù)化
- 緩存: 使用跨執(zhí)行狀態(tài)
- unittest.TestCase支持
- 運(yùn)行Nose用例
- 經(jīng)典xUnit風(fēng)格的setup/teardown
- 安裝和使用插件
- 插件編寫
- 編寫鉤子(hook)方法
- 運(yùn)行日志
- API參考
- 優(yōu)質(zhì)集成實(shí)踐
- 片狀測試
- Pytest導(dǎo)入機(jī)制及sys.path/PYTHONPATH
- 配置選項(xiàng)
- 示例及自定義技巧
- Bash自動補(bǔ)全設(shè)置
API參考-Fuctions
22-API參考-01-Functions
方法(Functions)
pytest.approx
斷言兩個數(shù)字(或兩組數(shù)字)在某個容差范圍內(nèi)彼此相等池摧。
由于浮點(diǎn)運(yùn)算的復(fù)雜性,我們直覺期望相等的數(shù)字并不總是如此:
0.1 + 0.2 == 0.3
False
編寫測試時通常會遇到此問題芜果,例如,確保浮點(diǎn)值是您期望的值玉雾。處理此問題的一種方法是斷言兩個浮點(diǎn)數(shù)等于某個適當(dāng)?shù)娜莶罘秶鷥?nèi):
abs((0.1 + 0.2) - 0.3) < 1e-6
True
但是翔试,這樣的比較寫作起來既乏味又難以理解。此外复旬,通常不鼓勵像上面這樣的絕對比較垦缅,因?yàn)闆]有適合所有情況的容忍度。 1e-6
對周圍的數(shù)字有好處1
驹碍,但對于非常大的數(shù)字而言太小而對于非常小的數(shù)字而言太大壁涎。最好將公差表示為預(yù)期值的一小部分,但這樣的相對比較更難以正確和簡潔地書寫志秃。
該approx
班采用語法是盡可能直觀執(zhí)行浮點(diǎn)比較:
from pytest import approx
>>> 0.1 + 0.2 == approx(0.3)
True
相同的語法也適用于數(shù)字序列:
(0.1 + 0.2, 0.2 + 0.4) == approx((0.3, 0.6))
True
字典值:
{'a': 0.1 + 0.2, 'b': 0.2 + 0.4} == approx({'a': 0.3, 'b': 0.6})
True
numpy
數(shù)組:
import numpy as np
>>> np.array([0.1, 0.2]) + np.array([0.2, 0.4]) == approx(np.array([0.3, 0.6]))
True
對于numpy
標(biāo)量的數(shù)組:
import numpy as np
>>> np.array([0.1, 0.2]) + np.array([0.2, 0.1]) == approx(0.3)
True
默認(rèn)情況下怔球,approx
將1e-6
其預(yù)期值的相對容差 (即百萬分之一)內(nèi)的數(shù)字視為相等。如果預(yù)期值是這樣的0.0
浮还,那么這種處理會產(chǎn)生令人驚訝的結(jié)果 竟坛,因?yàn)槌?code>0.0本身之外什么都不是0.0
。為了不那么令人驚訝地處理這種情況钧舌,approx
還要考慮在1e-12
其預(yù)期值的絕對容差內(nèi)的數(shù)字是相等的担汤。Infinity和NaN是特殊情況。無論相對容差如何洼冻,無窮大只被視為與自身相等崭歧。默認(rèn)情況下,NaN不被視為等于任何內(nèi)容撞牢,但您可以通過將nan_ok
參數(shù)設(shè)置為True 來使其等于自身率碾。(這是為了便于比較使用NaN的數(shù)組表示“無數(shù)據(jù)”。)
通過將參數(shù)傳遞給approx
構(gòu)造函數(shù)屋彪,可以更改相對容差和絕對容差:
1.0001 == approx(1)
False
>>> 1.0001 == approx(1, rel=1e-3)
True
>>> 1.0001 == approx(1, abs=1e-3)
True
如果您指定abs
但不指定rel
所宰,則比較將不會考慮相對容差。換句話說撼班,1e-6
如果超過指定的絕對容差歧匈,則默認(rèn)相對容差范圍內(nèi)的兩個數(shù)字仍將被視為不相等。如果同時指定兩個 abs
和rel
砰嘁,如果滿足任一公差,則數(shù)字將被視為相等:
1 + 1e-8 == approx(1)
True
>>> 1 + 1e-8 == approx(1, abs=1e-12)
False
>>> 1 + 1e-8 == approx(1, rel=1e-6, abs=1e-12)
True
如果您正在考慮使用approx
勘究,那么您可能想知道它與比較浮點(diǎn)數(shù)的其他好方法的比較矮湘。所有這些算法都基于相對和絕對容差,并且應(yīng)該在大多數(shù)情況下達(dá)成一致口糕,但它們確實(shí)存在有意義的差異:
-
math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)
:True如果相對誤差滿足WRT無論是a
或b
缅阳,或者如果絕對容差得到滿足。因?yàn)橄鄬θ莶钍?code>a和兩者一起計算的b
,所以該測試是對稱的(即既不是a
也不b
是“參考值”)十办。如果要進(jìn)行比較秀撇,則必須指定絕對容差,0.0
因?yàn)槟J(rèn)情況下沒有容差向族。僅在python> = 3.5中可用呵燕。 更多信息… -
numpy.isclose(a, b, rtol=1e-5, atol=1e-8)
:如果和之間的差值小于相對容差wrt 和絕對容差之a
和,b
則為真b
件相。由于相對容差僅計算為wrtb
再扭,因此該測試是不對稱的,您可以將其b
視為參考值夜矗。支持比較序列由numpy.allclose
泛范。提供。 更多信息… -
unittest.TestCase.assertAlmostEqual(a, b)
:如果a
并且b
在絕對容差范圍內(nèi)紊撕,則為真1e-7
罢荡。不考慮相對容差,并且不能改變絕對容差对扶,因此該功能不適用于非常大或非常小的數(shù)字区赵。此外,它只在子類中可用辩稽,unittest.TestCase
并且它很難看惧笛,因?yàn)樗蛔裱璓EP8。 更多信息… -
a == pytest.approx(b, rel=1e-6, abs=1e-12)
:如果滿足相對容差b
或者滿足絕對容差逞泄,則為真患整。由于相對容差僅計算為wrtb
,因此該測試是不對稱的喷众,您可以將其b
視為參考值各谚。在明確指定絕對公差而非相對公差的特殊情況下,僅考慮絕對公差到千。
警告
在3.2版中更改昌渤。
為了避免不一致的行為,TypeError
是提高了>
憔四,>=
膀息,<
和<=
比較。以下示例說明了問題:
0.1 + 1e-10 # calls approx(0.1).__gt__(0.1 + 1e-10)
assert 0.1 + 1e-10 > approx(0.1) # calls approx(0.1).__lt__(0.1 + 1e-10)
在第二個例子中了赵,人們期望 被調(diào)用潜支。但相反,用于比較柿汛。這是因?yàn)樨S富比較的調(diào)用層次結(jié)構(gòu)遵循固定行為冗酿。更多信息…approx(0.1).__le__(0.1 + 1e-10)``approx(0.1).__lt__(0.1 +1e-10)
pytest.fail
教程:Skip和xfail:處理無法成功的測試
使用給定消息顯式失敗執(zhí)行測試。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數(shù): |
pytest.skip
使用給定消息跳過執(zhí)行測試弱判。
應(yīng)僅在測試(設(shè)置襟沮,調(diào)用或拆除)期間或使用allow_module_level
標(biāo)志在收集期間調(diào)用此函數(shù)。此函數(shù)也可以在doctests中調(diào)用裕循。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數(shù): | allow_module_level(bool) - 允許在模塊級別調(diào)用此函數(shù)臣嚣,跳過模塊的其余部分。默認(rèn)為False剥哑。 |
注意:
最好在可能的情況下使用pytest.mark.skipif標(biāo)記來聲明在某些條件下跳過的測試硅则,例如不匹配的平臺或依賴項(xiàng)。同樣株婴,使用指令(請參閱doctest.SKIP)靜態(tài)跳過doctest怎虫。# doctest:+SKIP
pytest.importorskip
導(dǎo)入并返回請求的模塊modname
,或者如果無法導(dǎo)入模塊困介,則跳過當(dāng)前測試大审。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數(shù): |
- modname(str) - 要導(dǎo)入的模塊的名稱
-
minversion(str) - 如果給定,導(dǎo)入的模塊
__version__
屬性必須至少為此最小版本座哩,否則仍會跳過測試徒扶。 - reason(str) - 如果給定,則無法導(dǎo)入模塊時根穷,此原因顯示為消息姜骡。
pytest.xfail
由于給定的原因,強(qiáng)制執(zhí)行測試或設(shè)置功能屿良。
只應(yīng)在測試(設(shè)置圈澈,調(diào)用或拆卸)期間調(diào)用此函數(shù)。
注意
最好在可能的情況下使用pytest.mark.xfail標(biāo)記尘惧,在某些條件(如已知錯誤或缺少的功能)下聲明測試是否為xfailed康栈。
pytest.exit
退出測試過程。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數(shù): |
pytest.main
執(zhí)行進(jìn)程內(nèi)測試運(yùn)行后返回退出代碼。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數(shù): |
- args - 命令行參數(shù)列表贰逾。
- plugins - 初始化期間要自動注冊的插件對象列表饥臂。
pytest.param
在pytest.mark.parametrize調(diào)用或 參數(shù)化夾具中指定參數(shù)。
@pytest.mark.parametrize("test_input,expected", [
("3+5", 8),
pytest.param("6*9", 42, marks=pytest.mark.xfail),
])
def test_eval(test_input, expected):
assert eval(test_input) == expected
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數(shù): |
- values - 按順序的參數(shù)集值的變量args似踱。
- 標(biāo)記 - 要應(yīng)用于此參數(shù)集的單個標(biāo)記或標(biāo)記列表。
- id(str) - 屬于此參數(shù)集的id。
pytest.raises
教程:關(guān)于預(yù)期異常的斷言核芽。
斷言代碼塊/函數(shù)調(diào)用會引發(fā)expected_exception
或引發(fā)失敗異常囚戚。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數(shù): |
- match - 如果指定,則斷言異常與text或regex匹配
- 消息 - (自4.1棄用)如果指定轧简,提供了一種定制的失敗消息驰坊,如果異常沒有升高
|
使用pytest.raises
的上下文管理器,這將捕獲特定類型的異常:
with raises(ZeroDivisionError):
... 1/0
如果代碼塊沒有引發(fā)預(yù)期的異常(ZeroDivisionError
在上面的示例中)哮独,或者根本沒有異常拳芙,則檢查將失敗。
您還可以使用keyword參數(shù)match
來斷言異常與text或regex匹配:
with raises(ValueError, match='must be 0 or None'):
... raise ValueError("value must be 0 or None")
>>> with raises(ValueError, match=r'must be \d+/pre>):
... raise ValueError("value must be 42")
上下文管理器生成一個ExceptionInfo
對象皮璧,可用于檢查捕獲的異常的詳細(xì)信息:
with raises(ValueError) as exc_info:
... raise ValueError("value must be 42")
>>> assert exc_info.type is ValueError
>>> assert exc_info.value.args[0] == "value must be 42"
自4.1版本后不推薦使用:在上下文管理器表單中舟扎,您可以使用keyword參數(shù) message
指定在pytest.raises
檢查失敗時將顯示的自定義失敗消息。這已被棄用悴务,因?yàn)樗徽J(rèn)為是容易出錯的睹限,因?yàn)橛脩敉ǔR馕吨褂盟?code>match。
注意
當(dāng)pytest.raises
用作上下文管理器時讯檐,值得注意的是羡疗,應(yīng)用正常的上下文管理器規(guī)則,并且引發(fā)的異常必須是上下文管理器范圍內(nèi)的最后一行别洪。之后叨恨,在上下文管理器范圍內(nèi)的代碼行將不會被執(zhí)行。例如:
value = 15
>>> with raises(ValueError) as exc_info:
... if value > 10:
... raise ValueError("value must be <= 10")
... assert exc_info.type is ValueError # this will not execute
相反挖垛,必須采取以下方法(注意范圍的差異):
with raises(ValueError) as exc_info:
... if value > 10:
... raise ValueError("value must be <= 10")
...
>>> assert exc_info.type is ValueError
使用 pytest.mark.parametrize
使用pytest.mark.parametrize時 痒钝,可以對測試進(jìn)行參數(shù)化,使得某些運(yùn)行引發(fā)異常晕换,而其他運(yùn)行則不會午乓。
有關(guān)示例,請參閱參數(shù)化條件提升闸准。
遺產(chǎn)形式
可以通過傳遞一個名為lambda來指定一個可調(diào)用的:
raises(ZeroDivisionError, lambda: 1/0)
<ExceptionInfo ...>
或者你可以用參數(shù)指定一個任意的callable:
def f(x): return 1/x
...
>>> raises(ZeroDivisionError, f, 0)
<ExceptionInfo ...>
>>> raises(ZeroDivisionError, f, x=0)
<ExceptionInfo ...>
上面的表單完全受支持益愈,但不建議使用新代碼,因?yàn)樯舷挛墓芾砥鞅韱伪徽J(rèn)為更具可讀性且不易出錯夷家。
注意:
與Python中捕獲的異常對象類似蒸其,顯式清除對返回ExceptionInfo
對象的本地引用可以幫助Python解釋器加速其垃圾回收。
清除這些引用會中斷引用循環(huán)(ExceptionInfo
- >捕獲異常 - >幀堆棧引發(fā)異常 - >當(dāng)前幀堆棧 - >局部變量 - > ExceptionInfo
)库快,這會使Python保留從該循環(huán)引用的所有對象(包括當(dāng)前幀中的所有局部變量) )活著摸袁,直到下一個循環(huán)垃圾收集運(yùn)行。有關(guān)try
更多詳細(xì)信息义屏,請參閱官方Python 語句文檔靠汁。
pytest.deprecated_call
教程:確保代碼觸發(fā)棄用警告蜂大。
上下文管理器,可用于確保代碼塊觸發(fā)a DeprecationWarning
或PendingDeprecationWarning
:
import warnings
>>> def api_call_v2():
... warnings.warn('use v3 of this api', DeprecationWarning)
... return 200
>>> with deprecated_call():
... assert api_call_v2() == 200
deprecated_call
也可以通過傳遞函數(shù)來使用蝶怔,*args
并且*kwargs
在這種情況下奶浦,它將確保調(diào)用產(chǎn)生上面的警告類型之一。func(*args, **kwargs)
pytest.register_assert_rewrite
教程:斷言重寫踢星。
注冊一個或多個要在導(dǎo)入時重寫的模塊名稱澳叉。
此函數(shù)將確保此模塊或程序包內(nèi)的所有模塊將重寫其assert語句。因此沐悦,您應(yīng)確保在實(shí)際導(dǎo)入模塊之前調(diào)用此方法成洗,如果您是使用包的插件,則通常在init.py中調(diào)用藏否。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 舉: | TypeError - 如果給定的模塊名稱不是字符串瓶殃。 |
pytest.warns
斷言代碼會引發(fā)一類特定的警告。
具體來說秕岛,參數(shù)expected_warning
可以是警告類或警告類序列碌燕,并且with
塊內(nèi)部必須發(fā)出該類或類的警告。
該助手生成一個warnings.WarningMessage
對象列表继薛,每個警告引發(fā)一個對象修壕。
此函數(shù)可用作上下文管理器,pytest.raises
也可以使用任何其他方法 :
with warns(RuntimeWarning):
... warnings.warn("my warning", RuntimeWarning)
在上下文管理器表單中遏考,您可以使用keyword參數(shù)match
來斷言異常與text或regex匹配:
with warns(UserWarning, match='must be 0 or None'):
... warnings.warn("value must be 0 or None", UserWarning)
>>> with warns(UserWarning, match=r'must be \d+/pre>):
... warnings.warn("value must be 42", UserWarning)
>>> with warns(UserWarning, match=r'must be \d+/pre>):
... warnings.warn("this is not here", UserWarning)
Traceback (most recent call last):
...
Failed: DID NOT WARN. No warnings of type ...UserWarning... was emitted...
pytest.freeze_includes
教程:凍結(jié)pytest慈鸠。
返回pytest使用的模塊名稱列表,應(yīng)由cx_freeze包含灌具。