3.5 基本属性测试
3.5 基本屬性測試
開始編寫測試時(shí)要注意的另一個(gè)重要功能是ZIO Test支持開箱即用的基于屬性的測試。
 在基于屬性的測試中,測試框架不是您手動(dòng)生成輸入并驗(yàn)證期望的輸出,而是從您指定的潛在輸入分布中生成輸入的整個(gè)集合,并驗(yàn)證所有輸入的期望是否成立。
 基于屬性的測試可以極大地提高開發(fā)人員編寫測試的效率,并捕獲直到生產(chǎn)才發(fā)現(xiàn)的錯(cuò)誤,因?yàn)樗梢允箿y試框架立即生成大量測試用例,其中包括開發(fā)人員最初可能沒有考慮過的用例。
 但是,必須小心進(jìn)行屬性測試,以確保使用正確的生成值分布,包括足夠數(shù)量的“拐角案例”(例如,空集合,具有最小值和最大值的整數(shù))以及足夠的生成值空間覆蓋生產(chǎn)中可能看到的值的范圍(例如,長字符串,非ASCII字符集中的字符串)。
 ZIO Test通過其Gen數(shù)據(jù)類型和運(yùn)算符檢查家族來支持屬性。 Gen [R,A]代表需要環(huán)境R的A值的生成器。根據(jù)實(shí)現(xiàn)方式,生成器可以是無限的或有限的,并且可以是隨機(jī)的或確定的。
 ZIO測試在Gen隨播對(duì)象中包含各種標(biāo)準(zhǔn)數(shù)據(jù)類型的生成器。例如,我們可以使用anyInt生成器創(chuàng)建一個(gè)整數(shù)值生成器。
一旦有了生成器,就可以使用check運(yùn)算符使用該生成器創(chuàng)建測試。例如:
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))}})}注意,編寫基于屬性的測試的方式與編寫普通測試的方式非常相似。
 我們?nèi)匀皇褂胻estM方法標(biāo)記測試。基于屬性的測試將始終使用testM而不是test,因?yàn)檫\(yùn)行基于屬性的測試本身會(huì)涉及effect。
在測試中,我們調(diào)用check運(yùn)算符,將要使用的每個(gè)生成器指定為參數(shù)。 ZIO
 Test具有針對(duì)不同數(shù)量的生成器的檢查運(yùn)算符的重載變體,因此您可以對(duì)單個(gè)生成器或多個(gè)不同的生成器使用check,如上例所示。
 然后,我們提供一個(gè)可以訪問每個(gè)生成的值并使用assert或assert運(yùn)算符返回測試結(jié)果的函數(shù),就像我們?cè)谏厦婢帉懙臏y試中使用的一樣。然后,測試框架將重復(fù)采樣值的組合并測試這些樣本,直到發(fā)現(xiàn)失敗或測試“足夠”數(shù)量的樣本而未發(fā)現(xiàn)失敗。
 檢查運(yùn)算符有幾種變體。最重要的是checkM,它類似于check,不同之處在于它允許我們?cè)诨趯傩缘臏y試中執(zhí)行效果。還有checkN變體,可以指定要測試的樣本數(shù)量,而checkAll變體可以測試有限生成器中的所有樣本。
 編寫基于屬性的測試的許多工作往往是編寫生成器本身。如果我們要生成的值是ZIO或Scala標(biāo)準(zhǔn)庫中的數(shù)據(jù)類型,并且我們不需要任何特殊的分布,那么我們通常可以使用現(xiàn)有的生成器,就像上面使用的intGen一樣。
 當(dāng)我們需要為自己的數(shù)據(jù)類型創(chuàng)建生成器時(shí),可以使用現(xiàn)有的Gen構(gòu)造函數(shù)和Gen上的運(yùn)算符來創(chuàng)建所需的生成器。到目前為止,從我們對(duì)ZIO的了解中,我們已經(jīng)對(duì)其中許多操作感到熟悉。
 舉例來說,假設(shè)我們要為已定義的User數(shù)據(jù)類型創(chuàng)建生成器。
由于User是一種數(shù)據(jù)類型,因此我們定義了ZIO測試中不存在用于User的生成器。
 此外,基于對(duì)域的理解,我們知道User值必須滿足某些在類型簽名中未捕獲的屬性。
名稱始終由ASCII字符組成
對(duì)于成年人來說,年齡總是屬于自然壽命,例如18歲和120.
我們可以使用現(xiàn)有的anyASCIIString為名稱實(shí)現(xiàn)生成器。
val genName: Gen[Random with Sized, String] = Gen.anyASCIIString// genName: Gen[Random with Sized, String] = Gen( // zio.stream.ZStream$$anon$1@3ae44cd1// )此生成器需要一個(gè)我們從未見過的服務(wù),它是ZIO
 Test特有的服務(wù),它可以控制所生成值的“大小”,例如,我們應(yīng)該生成一個(gè)列表的大小,或者在這種情況下,一個(gè)String的大小。
 。 對(duì)于年齡生成器,我們可以使用int構(gòu)造函數(shù),該構(gòu)造函數(shù)生成指定范圍內(nèi)的整數(shù)值。
實(shí)現(xiàn)這兩個(gè)生成器后,剩下的就是將它們組合起來,從概念上從genName采樣一個(gè)名稱,從genAge采樣一個(gè)年齡,然后將兩者結(jié)合以生成User值。 Gen數(shù)據(jù)類型支持許多我們已經(jīng)熟悉的運(yùn)算符,包括map,flatMap和zipWith,因此我們實(shí)際上可以很容易地做到這一點(diǎn)。
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// )我們現(xiàn)在有了一個(gè)User值生成器,可以在任何check變量中使用它來為基于屬性的測試生成User值!
總結(jié)
以上是生活随笔為你收集整理的3.5 基本属性测试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 迭代器 iter()
- 下一篇: 一篇文章带你搞定 SpringBoot
