目錄:
- 安裝及入門
- 使用和調用方法
- 原有TestSuite使用方法
- 斷言的編寫和報告
- Pytest fixtures:清晰 模塊化 易擴展
- 使用Marks標記測試用例
- Monkeypatching/對模塊和環境進行Mock
- 使用tmp目錄和文件
- 捕獲stdout及stderr輸出
- 捕獲警告信息
- 模塊及測試文件中集成doctest測試
- skip及xfail: 處理不能成功的測試用例
- Fixture方法及測試用例的參數化
- 緩存: 使用跨執行狀態
- unittest.TestCase支持
- 運行Nose用例
- 經典xUnit風格的setup/teardown
- 安裝和使用插件
- 插件編寫
- 編寫鉤子(hook)方法
- 運行日志
- API參考
- 優質集成實踐
- 片狀測試
- Pytest導入機制及sys.path/PYTHONPATH
- 配置選項
- 示例及自定義技巧
- Bash自動補全設置
API參考-Fuctions
22-API參考-01-Functions
方法(Functions)
pytest.approx
斷言兩個數字(或兩組數字)在某個容差范圍內彼此相等。
0.1 + 0.2 == 0.3
False
編寫測試時通常會遇到此問題,例如,確保浮點值是您期望的值。處理此問題的一種方法是斷言兩個浮點數等于某個適當的容差范圍內:
abs((0.1 + 0.2) - 0.3) < 1e-6
True
但是,這樣的比較寫作起來既乏味又難以理解。此外,通常不鼓勵像上面這樣的絕對比較,因為沒有適合所有情況的容忍度。 1e-6
對周圍的數字有好處1
,但對于非常大的數字而言太小而對于非常小的數字而言太大。最好將公差表示為預期值的一小部分,但這樣的相對比較更難以正確和簡潔地書寫。
該approx
班采用語法是盡可能直觀執行浮點比較:
from pytest import approx
>>> 0.1 + 0.2 == approx(0.3)
True
相同的語法也適用于數字序列:
(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
數組:
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
標量的數組:
import numpy as np
>>> np.array([0.1, 0.2]) + np.array([0.2, 0.1]) == approx(0.3)
True
默認情況下,approx
將1e-6
其預期值的相對容差 (即百萬分之一)內的數字視為相等。如果預期值是這樣的0.0
,那么這種處理會產生令人驚訝的結果 ,因為除了0.0
本身之外什么都不是0.0
。為了不那么令人驚訝地處理這種情況,approx
還要考慮在1e-12
其預期值的絕對容差內的數字是相等的。Infinity和NaN是特殊情況。無論相對容差如何,無窮大只被視為與自身相等。默認情況下,NaN不被視為等于任何內容,但您可以通過將nan_ok
參數設置為True 來使其等于自身。(這是為了便于比較使用NaN的數組表示“無數據”。)
通過將參數傳遞給approx
構造函數,可以更改相對容差和絕對容差:
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
如果超過指定的絕對容差,則默認相對容差范圍內的兩個數字仍將被視為不相等。如果同時指定兩個 abs
和rel
,如果滿足任一公差,則數字將被視為相等:
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
,那么您可能想知道它與比較浮點數的其他好方法的比較。所有這些算法都基于相對和絕對容差,并且應該在大多數情況下達成一致,但它們確實存在有意義的差異:
-
math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)
:True如果相對誤差滿足WRT無論是a
或b
,或者如果絕對容差得到滿足。因為相對容差是a
和兩者一起計算的b
,所以該測試是對稱的(即既不是a
也不b
是“參考值”)。如果要進行比較,則必須指定絕對容差,0.0
因為默認情況下沒有容差。僅在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
在絕對容差范圍內,則為真1e-7
。不考慮相對容差,并且不能改變絕對容差,因此該功能不適用于非常大或非常小的數字。此外,它只在子類中可用,unittest.TestCase
并且它很難看,因為它不遵循PEP8。 更多信息… -
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)
在第二個例子中,人們期望 被調用。但相反,用于比較。這是因為豐富比較的調用層次結構遵循固定行為。更多信息…approx(0.1).__le__(0.1 + 1e-10)``approx(0.1).__lt__(0.1 +1e-10)
pytest.fail
教程:Skip和xfail:處理無法成功的測試
使用給定消息顯式失敗執行測試。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數: |
pytest.skip
使用給定消息跳過執行測試。
應僅在測試(設置,調用或拆除)期間或使用allow_module_level
標志在收集期間調用此函數。此函數也可以在doctests中調用。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數: | allow_module_level(bool) - 允許在模塊級別調用此函數,跳過模塊的其余部分。默認為False。 |
注意:
最好在可能的情況下使用pytest.mark.skipif標記來聲明在某些條件下跳過的測試,例如不匹配的平臺或依賴項。同樣,使用指令(請參閱doctest.SKIP)靜態跳過doctest。# doctest:+SKIP
pytest.importorskip
導入并返回請求的模塊modname
,或者如果無法導入模塊,則跳過當前測試。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數: |
- modname(str) - 要導入的模塊的名稱
-
minversion(str) - 如果給定,導入的模塊
__version__
屬性必須至少為此最小版本,否則仍會跳過測試。 - reason(str) - 如果給定,則無法導入模塊時,此原因顯示為消息。
pytest.xfail
由于給定的原因,強制執行測試或設置功能。
只應在測試(設置,調用或拆卸)期間調用此函數。
注意
最好在可能的情況下使用pytest.mark.xfail標記,在某些條件(如已知錯誤或缺少的功能)下聲明測試是否為xfailed。
pytest.exit
退出測試過程。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數: |
pytest.main
執行進程內測試運行后返回退出代碼。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數: |
- args - 命令行參數列表。
- plugins - 初始化期間要自動注冊的插件對象列表。
pytest.param
在pytest.mark.parametrize調用或 參數化夾具中指定參數。
@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>
| 參數: |
- values - 按順序的參數集值的變量args。
- 標記 - 要應用于此參數集的單個標記或標記列表。
- id(str) - 屬于此參數集的id。
pytest.raises
教程:關于預期異常的斷言。
斷言代碼塊/函數調用會引發expected_exception
或引發失敗異常。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 參數: |
- match - 如果指定,則斷言異常與text或regex匹配
- 消息 - (自4.1棄用)如果指定,提供了一種定制的失敗消息,如果異常沒有升高
|
使用pytest.raises
的上下文管理器,這將捕獲特定類型的異常:
with raises(ZeroDivisionError):
... 1/0
如果代碼塊沒有引發預期的異常(ZeroDivisionError
在上面的示例中),或者根本沒有異常,則檢查將失敗。
您還可以使用keyword參數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
對象,可用于檢查捕獲的異常的詳細信息:
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參數 message
指定在pytest.raises
檢查失敗時將顯示的自定義失敗消息。這已被棄用,因為它被認為是容易出錯的,因為用戶通常意味著使用它match
。
注意
當pytest.raises
用作上下文管理器時,值得注意的是,應用正常的上下文管理器規則,并且引發的異常必須是上下文管理器范圍內的最后一行。之后,在上下文管理器范圍內的代碼行將不會被執行。例如:
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時 ,可以對測試進行參數化,使得某些運行引發異常,而其他運行則不會。
有關示例,請參閱參數化條件提升。
遺產形式
可以通過傳遞一個名為lambda來指定一個可調用的:
raises(ZeroDivisionError, lambda: 1/0)
<ExceptionInfo ...>
或者你可以用參數指定一個任意的callable:
def f(x): return 1/x
...
>>> raises(ZeroDivisionError, f, 0)
<ExceptionInfo ...>
>>> raises(ZeroDivisionError, f, x=0)
<ExceptionInfo ...>
上面的表單完全受支持,但不建議使用新代碼,因為上下文管理器表單被認為更具可讀性且不易出錯。
注意:
與Python中捕獲的異常對象類似,顯式清除對返回ExceptionInfo
對象的本地引用可以幫助Python解釋器加速其垃圾回收。
清除這些引用會中斷引用循環(ExceptionInfo
- >捕獲異常 - >幀堆棧引發異常 - >當前幀堆棧 - >局部變量 - > ExceptionInfo
),這會使Python保留從該循環引用的所有對象(包括當前幀中的所有局部變量) )活著,直到下一個循環垃圾收集運行。有關try
更多詳細信息,請參閱官方Python 語句文檔。
pytest.deprecated_call
教程:確保代碼觸發棄用警告。
上下文管理器,可用于確保代碼塊觸發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
也可以通過傳遞函數來使用,*args
并且*kwargs
在這種情況下,它將確保調用產生上面的警告類型之一。func(*args, **kwargs)
pytest.register_assert_rewrite
教程:斷言重寫。
注冊一個或多個要在導入時重寫的模塊名稱。
此函數將確保此模塊或程序包內的所有模塊將重寫其assert語句。因此,您應確保在實際導入模塊之前調用此方法,如果您是使用包的插件,則通常在init.py中調用。
<colgroup><col class="field-name" style="hyphens: manual;"><col class="field-body"></colgroup>
| 舉: | TypeError - 如果給定的模塊名稱不是字符串。 |
pytest.warns
教程:使用警告功能發出警告
斷言代碼會引發一類特定的警告。
具體來說,參數expected_warning
可以是警告類或警告類序列,并且with
塊內部必須發出該類或類的警告。
該助手生成一個warnings.WarningMessage
對象列表,每個警告引發一個對象。
此函數可用作上下文管理器,pytest.raises
也可以使用任何其他方法 :
with warns(RuntimeWarning):
... warnings.warn("my warning", RuntimeWarning)
在上下文管理器表單中,您可以使用keyword參數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
教程:凍結pytest。
返回pytest使用的模塊名稱列表,應由cx_freeze包含。