介紹
無論你使用哪種編程語言或框架,測試都非常重要。Hypothesis
是 Python 的一個高級測試庫。它允許編寫測試用例時參數化,然后生成使測試失敗的簡單易懂的測試數據。可以用更少的工作在代碼中發現更多的bug。該測試庫覆蓋了大多數情況,并且確實可以幫助你查找代碼中的錯誤。
這篇文章為展示了如何使用Hypothesis
在Python中進行測試,并提供了一些示例。
我們如何區分測試?
在我們開始進行基于屬性的測試之前,我們需要知道測試的一般區別。有不同的分組測試方法,兩種最常見的方法基于測試方法和測試級別。讓我們從大多數人已經聽說的測試級別開始。本質上,存在四個測試級別(盡管人們可能也知道或定義其他級別):
- 單元測試
- 集成測試
- 系統測試
- 端到端測試
不同測試級別側重專注于不同的事物。單元測試側重于軟件的特定部分或功能。這可以是單個功能或功能的一部分。相反,集成測試側重于通過軟件組件的接口進行協作。系統測試甚至更進一步,可以測試整個系統。
現在,我們將看看存在的各種各樣的測試方法。
最常見和已知的是靜態和動態測試。所謂靜態測試(static testing)就是不實際運行被測軟件,而只是靜態地檢查程序代碼、界面或文檔中可能存在的錯誤的過程。如果軟件或其部分實際執行,我們稱之為動態測試。編寫單元測試和集成測試屬于動態測試。
另一種常見的方法是盒式方法。基本上,它可以分為白盒測試和黑盒測試(以及灰盒測試作為兩者的混合)。白盒測試可驗證程序的內部結構或工作情況。黑盒測試與之相反,在黑盒測試中,應用程序被視為黑盒,并且對其交互進行測試。這意味著在不了解內部實現的情況下測試功能。
什么是基于屬性的測試?
現在,我們快速了解了如何區分測試,您可能會問:什么是基于屬性的測試?
基于屬性的測試技術( Property-based testing),是指編寫對你的代碼來說為真的邏輯語句(即“屬性”),然后使用自動化工具來生成測試輸入(一般來說,是指某種特定類型的隨機生成輸入數據),并觀察程序接受該輸入時屬性是否保持不變。如果某個輸入違反了某一條屬性,則用戶證明程序存在一處錯誤,并找到一個能夠演示該錯誤的便捷示例。
使用Hypothesis
進行基于屬性的測試
讓我們舉一個簡單的例子。假設您有兩個函數crement()
和decrement()
。一個示例實現可能如下所示:
#?increment_decrement.py
def?increment(number:?int)?->?int:
????return?number?+?1
def?decrement(number:?int)?->?int:
????return?number?-?1
您可能會為兩者編寫單元測試代碼,如下所示:
#?test_increment_decrement_pytest.py
from?increment_decrement?import?decrement
from?increment_decrement?import?increment
def?test_increment():
????x?=?5
????expected?=?6
????actual?=?increment(x)
????assert?actual?==?expected
def?test_decrement():
????x?=?5
????expected?=?4
????actual?=?decrement(x)
????assert?actual?==?expected
注意:測試代碼是使用pytest框架編寫的。
當然,您可以編寫更多的測試腳本來測試具有不同值的兩個函數,甚至可以對測試進行參數化。但是,最后您將使用預定義的值來測試這兩個功能。
使用基于屬性的測試庫(例如Hypothesis )編寫測試是不同的。在這里,您可以指定要測試的類型以及軟件的工作方式或行為方式。然后該庫根據指定的類型生成隨機值來進行實際測試功能。
讓我們看看如何使用Hypothesis
來測試我們的兩個功能。
#?test_increment_decrement_hypothesis.py
from?hypothesis?import?given
import?hypothesis.strategies?as?st
from?increment_decrement?import?decrement
from?increment_decrement?import?increment
@given(st.integers())
def?test_increment(x):
????expected?=?x?+?1
????actual?=?increment(x)
????assert?actual?==?expected
@given(st.integers())
def?test_decrement(x):
????expected?=?x?-?1
????actual?=?decrement(x)
????assert?actual?==?expected
如您所見,這兩個測試腳本都有一個參數x
。x
的值是由Hypothesis
使用integers()
方法生成的。Hypothesis
提供了各種方法。本質上,這些方法對應于內置類型或其他結構,并生成與給定類型匹配的隨機數據。
聽起來不錯,不是嗎?但是,如果我們想測試具有特定值的函數以確保它也可以使用該值怎么辦?Hypothesis
提供了一個@example()
裝飾器,您可以在其中定義一個值,即使該值不屬于隨機生成的測試數據集,也可以將該值傳遞給相應的函數。
讓我們舉個簡單的例子:
#?div.py
def?div(dividend:?int,?divisor:?int)?->?int:
????return?dividend?//?divisor
我們定義了一個函數div()
,該函數接受一個除數和一個被除數并返回兩者的商。請注意,這兩個參數都是整型數據,因此結果也應該是整型數據,我們使用Python的//
運算符執行整數除法。
為了測試div()
函數,我們創建了一個新的測試文件test_div.py
并編寫了一個名為test_div()
的測試腳本。
#?test_div.py
from?hypothesis?import?example
from?hypothesis?import?given
import?hypothesis.strategies?as?st
from?div?import?div
@given(dividend=st.integers(),?divisor=st.integers())
def?test_div(dividend,?divisor):
????if?divisor?==?0:
????????expected?=?-1
????else:
????????expected?=?dividend?//?divisor
????actual?=?div(dividend,?divisor)
????assert?actual?==?expected
同樣,我們使用Hypothesis
的integers()
方法生成除數和被除數的值。我們編寫的測試腳本可能通過也可能不會通過,具體取決于執行時Hypothesis
產生的值。為了確保始終將值0
傳遞給div()
函數,我們將@example(1,0)
添加到test_div()
函數。因此,即使div()
不在隨機生成的數據集中,也至少會用除數的值0
調用一次。
如果我們按原樣運行測試腳本,則test_div()
將始終失敗。因此,讓我們修改div()
函數來處理這種情況并使測試通過:
#?div.py
def?div(dividend:?int,?divisor:?int)?->?int:
????if?divisor?==?0:
????????return?-1
????return?dividend?//?divisor
概要
本文主要講了什么是基于屬性的測試以及為什么有用。此外,您快速瀏覽了Hypothesis
庫,該庫使您可以編寫基于屬性的測試并與pytest測試一起執行。
文末福利
明哥整理了?21 張 Python 代碼速查表,每一張都是國外的大師總結的,非常實用 ~還有?2 張高清的?PyCharm 快捷鍵一覽圖,一張?Windows?,一張?Mac,放在桌面上,需要的時候打開一查,非常方便。。
怎么獲取呢?

添加明哥微信,備注 "速查表" 和 "快捷鍵" 獲取
- EOF -
推薦閱讀??點擊標題可跳轉求你了,別再用?print?調試代碼了
GitHub 捍衛開發者!重新上架 7.2 萬星開源項目 youtube-dl
使用 Python 打印漂亮的表格,這兩項基本功你可會?
別這樣直接運行Python命令,否則電腦等于“裸奔”
5 個 Git 工作流,改善你的開發流程
8 個 Jupyter Notebook Tips,隱藏得太深了
用 Python 讀取資源文件?這個技巧保你漲姿勢
覺得本文對你有幫助?請分享給更多人