3.5 基本属性测试
3.5 基本屬性測試
開始編寫測試時要注意的另一個重要功能是ZIO Test支持開箱即用的基于屬性的測試。
在基于屬性的測試中,測試框架不是您手動生成輸入并驗證期望的輸出,而是從您指定的潛在輸入分布中生成輸入的整個集合,并驗證所有輸入的期望是否成立。
基于屬性的測試可以極大地提高開發人員編寫測試的效率,并捕獲直到生產才發現的錯誤,因為它可以使測試框架立即生成大量測試用例,其中包括開發人員最初可能沒有考慮過的用例。
但是,必須小心進行屬性測試,以確保使用正確的生成值分布,包括足夠數量的“拐角案例”(例如,空集合,具有最小值和最大值的整數)以及足夠的生成值空間覆蓋生產中可能看到的值的范圍(例如,長字符串,非ASCII字符集中的字符串)。
ZIO Test通過其Gen數據類型和運算符檢查家族來支持屬性。 Gen [R,A]代表需要環境R的A值的生成器。根據實現方式,生成器可以是無限的或有限的,并且可以是隨機的或確定的。
ZIO測試在Gen隨播對象中包含各種標準數據類型的生成器。例如,我們可以使用anyInt生成器創建一個整數值生成器。
一旦有了生成器,就可以使用check運算符使用該生成器創建測試。例如:
object ExampleSpec extends DefaultRunnableSpec {def spec = suite("ExampleSpec")(testM("integer addition is associative") {check(intGen, intGen, intGen) {(x, y, z) =>val left = (x + y) + zval right = x + (y + z) assert (left)(equalTo(right))}})}注意,編寫基于屬性的測試的方式與編寫普通測試的方式非常相似。
我們仍然使用testM方法標記測試。基于屬性的測試將始終使用testM而不是test,因為運行基于屬性的測試本身會涉及effect。
在測試中,我們調用check運算符,將要使用的每個生成器指定為參數。 ZIO
Test具有針對不同數量的生成器的檢查運算符的重載變體,因此您可以對單個生成器或多個不同的生成器使用check,如上例所示。
然后,我們提供一個可以訪問每個生成的值并使用assert或assert運算符返回測試結果的函數,就像我們在上面編寫的測試中使用的一樣。然后,測試框架將重復采樣值的組合并測試這些樣本,直到發現失敗或測試“足夠”數量的樣本而未發現失敗。
檢查運算符有幾種變體。最重要的是checkM,它類似于check,不同之處在于它允許我們在基于屬性的測試中執行效果。還有checkN變體,可以指定要測試的樣本數量,而checkAll變體可以測試有限生成器中的所有樣本。
編寫基于屬性的測試的許多工作往往是編寫生成器本身。如果我們要生成的值是ZIO或Scala標準庫中的數據類型,并且我們不需要任何特殊的分布,那么我們通常可以使用現有的生成器,就像上面使用的intGen一樣。
當我們需要為自己的數據類型創建生成器時,可以使用現有的Gen構造函數和Gen上的運算符來創建所需的生成器。到目前為止,從我們對ZIO的了解中,我們已經對其中許多操作感到熟悉。
舉例來說,假設我們要為已定義的User數據類型創建生成器。
由于User是一種數據類型,因此我們定義了ZIO測試中不存在用于User的生成器。
此外,基于對域的理解,我們知道User值必須滿足某些在類型簽名中未捕獲的屬性。
名稱始終由ASCII字符組成
對于成年人來說,年齡總是屬于自然壽命,例如18歲和120.
我們可以使用現有的anyASCIIString為名稱實現生成器。
val genName: Gen[Random with Sized, String] = Gen.anyASCIIString// genName: Gen[Random with Sized, String] = Gen( // zio.stream.ZStream$$anon$1@3ae44cd1// )此生成器需要一個我們從未見過的服務,它是ZIO
Test特有的服務,它可以控制所生成值的“大小”,例如,我們應該生成一個列表的大小,或者在這種情況下,一個String的大小。
。 對于年齡生成器,我們可以使用int構造函數,該構造函數生成指定范圍內的整數值。
實現這兩個生成器后,剩下的就是將它們組合起來,從概念上從genName采樣一個名稱,從genAge采樣一個年齡,然后將兩者結合以生成User值。 Gen數據類型支持許多我們已經熟悉的運算符,包括map,flatMap和zipWith,因此我們實際上可以很容易地做到這一點。
val genUser: Gen[Random with Sized, User] = for {name <- genNameage <- genAge} yield User(name, age)// genUser: Gen[Random with Sized, User] = Gen( // zio.stream.ZStream$$anon$1@695a724a// )我們現在有了一個User值生成器,可以在任何check變量中使用它來為基于屬性的測試生成User值!
總結
以上是生活随笔為你收集整理的3.5 基本属性测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 迭代器 iter()
- 下一篇: 数字图像处理100问—03二值化(Thr