精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

單元測(cè)試框架的對(duì)比

原創(chuàng) 精選
開(kāi)發(fā) 測(cè)試
在開(kāi)發(fā)過(guò)程中,我發(fā)現(xiàn) JUnit 并不總是那么好用。它在一些情況下需要耗費(fèi)挺多精力才能編寫(xiě)出讓人滿意的測(cè)試。

作者 | 高悅翔

在我們?nèi)粘5?TDD 開(kāi)發(fā)中,永遠(yuǎn)繞不過(guò)去的就是要編寫(xiě)測(cè)試。而對(duì)于一個(gè) Java 程序員,JUnit 似乎是一個(gè)不二的選擇。它的確是一個(gè)十分優(yōu)秀的工具,在大多數(shù)情況下都能夠幫助我們完成測(cè)試的工作。

但是在開(kāi)發(fā)過(guò)程中,我發(fā)現(xiàn) JUnit 并不總是那么好用。它在一些情況下需要耗費(fèi)挺多精力才能編寫(xiě)出讓人滿意的測(cè)試。

JUnit 不擅長(zhǎng)的事情

一個(gè)讓人滿意的測(cè)試,應(yīng)該能夠清晰地體現(xiàn)被測(cè)試的目標(biāo)、測(cè)試的目的以及測(cè)試的輸入輸出,并且應(yīng)遵循 DRY 原則,盡可能的減少測(cè)試中的重復(fù)內(nèi)容。

JUnit 可以通過(guò)設(shè)計(jì)測(cè)試方法名和組織方法內(nèi)的代碼的方式清晰地表達(dá)意圖,也可以通過(guò)參數(shù)化測(cè)試來(lái)減少相同測(cè)試目的的代碼重復(fù)。但是它在這些地方都做得不夠好。

清晰表達(dá)測(cè)試的目的

在使用 JUnit 時(shí),清晰的表達(dá)測(cè)試意圖并不是總能做到的事情。這主要體現(xiàn)在兩個(gè)方面。

(1) 如何命名測(cè)試方法

第一個(gè)體現(xiàn)就是在使用 Java 編寫(xiě)測(cè)試時(shí),采用什么樣的命名風(fēng)格來(lái)命名測(cè)試。是為了代碼風(fēng)格的統(tǒng)一而選擇駝峰?還是為了更高的可讀性選擇下劃線?這個(gè)問(wèn)題在不同的項(xiàng)目中有不同的實(shí)踐,看起來(lái)是沒(méi)有一個(gè)統(tǒng)一的認(rèn)識(shí)。

而這個(gè)問(wèn)題的根源是 JUnit 的測(cè)試名稱是 Java 的方法名,而 Java 的方法名又不能在其中插入空格。所以除了下面要介紹的兩種測(cè)試工具外,采用 Kotlin 來(lái)編寫(xiě) JUnit 也是一種方式。

(2) 如何組織方法內(nèi)的代碼

第二個(gè)體現(xiàn)就是 JUnit 對(duì)測(cè)試方法內(nèi)部如何編寫(xiě)沒(méi)有強(qiáng)制的規(guī)定。這就意味著我可以在測(cè)試?yán)锩嫒我獾亟M織代碼,比如在一個(gè)測(cè)試方法里面對(duì)一個(gè)方法調(diào)用多次并驗(yàn)證每一次的結(jié)果,或者把調(diào)用測(cè)試目錄的邏輯和準(zhǔn)備數(shù)據(jù)的邏輯以及驗(yàn)證邏輯混合到一起。 總之這樣的結(jié)果就是測(cè)試方法內(nèi)的代碼組織方式千奇百怪,每當(dāng)閱讀別人編寫(xiě)的測(cè)試的時(shí)候,總是要花上好幾分鐘才能知道這些代碼到底在干什么。

對(duì)于這個(gè)問(wèn)題,我個(gè)人會(huì)選擇使用注釋來(lái)標(biāo)注一下 given 、 when 、 then,并且給 IDEA 設(shè)置了 live template 方便插入它們。

又不是不能用的參數(shù)化測(cè)試

如果說(shuō)不能清晰地表達(dá)測(cè)試意圖這個(gè)問(wèn)題還有一些 workaround 可以繞過(guò)去的話,JUnit 那僅僅是能用的參數(shù)化測(cè)試功能就沒(méi)有什么好辦法可以繞過(guò)去了。

JUnit 提供了各種 Source 注解來(lái)為參數(shù)化測(cè)試提供數(shù)據(jù),但是這個(gè)功能實(shí)在是太弱了,很難讓人滿意。

難以讓人滿意的第一個(gè)原因是,各種 Source 注解基本上只能支持 7 種基本類型再加上 String, Enum 和 Class 類型。如果想要使用其他類型的實(shí)例作為參數(shù)的話,就必須要使用 MethodSource 或者 ArgumentsSource 注解。

這就導(dǎo)致了第二個(gè)原因:這兩個(gè)注解需要單獨(dú)寫(xiě)一個(gè)靜態(tài)方法或一個(gè) ArgumentProvider 的實(shí)現(xiàn),這就導(dǎo)致很難把測(cè)試參數(shù)寫(xiě)到測(cè)試代碼旁邊。并且 Arguments.of() 方法并不利于閱讀測(cè)試參數(shù)。

這兩點(diǎn)導(dǎo)致測(cè)試的可讀性下降。而按照“測(cè)試即文檔”的原則,我們應(yīng)該盡力去保證測(cè)試的可讀性。

第三個(gè)原因則是來(lái)自 ParameterizedTest 注解。它的 name 字段可以使用參數(shù)的索引值來(lái)把參數(shù)填入模板中,生成更加可讀的測(cè)試名稱。

但是它的功能也僅限于此了。因?yàn)檫@個(gè)模板只能使用索引值,不能使用索引后再調(diào)用里面的方法或者字段。所以如果我們的參數(shù)是一個(gè)復(fù)雜對(duì)象,那么一定要重寫(xiě) toString 方法才能得到滿意的輸出。但是這又違背了編寫(xiě)測(cè)試的原則之一——不能為了測(cè)試而添加實(shí)現(xiàn)代碼。

如果我們一定要得到一個(gè)更加表意的測(cè)試名稱,那么添加一個(gè)專用的測(cè)試參數(shù)也能做到。但是這又會(huì)導(dǎo)致 IDE 或者構(gòu)建工具的警告,因?yàn)樗鼈冋J(rèn)為這個(gè)參數(shù)沒(méi)有被使用。

總之,盡管 JUnit 可以解決絕大多數(shù)問(wèn)題,但是在這么幾個(gè)小地方卻做的不是那么完美。

那么有沒(méi)有什么工具可以作為 JUnit 的替代呢?當(dāng)然是有的。下面我將按照我接觸的順序來(lái)介紹兩種種測(cè)試框架。可以在 GitHub 上找到下面例子的完整代碼。

使用 Spock 作為測(cè)試框架

Spock是一個(gè)用 Groovy 編寫(xiě)的測(cè)試框架,按照 given/when/then 的結(jié)構(gòu)定義 dsl,能夠讓測(cè)試更加的語(yǔ)義化。它的一大特點(diǎn)是 Data Driven Test,可以方便的編寫(xiě)參數(shù)化測(cè)試。

我曾在兩個(gè)項(xiàng)目上嘗試過(guò)使用 Spock 作為測(cè)試框架,幾乎沒(méi)有遇到過(guò)無(wú)法解決的問(wèn)題。

如何使用 Spock

我們來(lái)看一個(gè)最簡(jiǎn)單的例子:

class MarsRoverSpockTest extends Specification { // 1
def "should return mars rover position and direction when mars rover report"() { //2
given: // 3.1
def marsRover = MarsRoverFixture.buildMarsRover(
position: new Position(1, 2),
direction: Direction.EAST,
)

when: // 3.2
def marsRoverInfo = marsRover.report()

then: // 3.3
marsRoverInfo.position == new Position(1, 2)
marsRoverInfo.direction == Direction.EAST
}
}

(1) 每一個(gè)測(cè)試都需要繼承抽象類 Specification;

(2) 可以使用字符串來(lái)命名測(cè)試;

(3) Spock 定義了一些 block,這里的 given 、 when 、 then 都是 block。

  • given block 負(fù)責(zé)測(cè)試的 setup 工作
  • when block 可以是任意代碼,不過(guò)最好是對(duì)測(cè)試目標(biāo)的調(diào)用。它總是和 then 一起出現(xiàn)
  • then block 用來(lái)斷言。這里不需要任何的 assertion,只需要編寫(xiě)返回值是 boolean 的表達(dá)式即可

Spock 有非常友好的測(cè)試報(bào)告輸出。如果我們把上面的斷言特意改錯(cuò),就能得到這樣的測(cè)試輸出:

Condition not satisfied:

movedMarsRover.position == movedPosition
| | | |
| | | Position(x=-2, y=2)
| | false
| Position(x=-1, y=2)
MarsRover(position=Position(x=-1, y=2), direction=WEST)

在這個(gè)輸出里面,我們可以清晰的看出表達(dá)式兩端的值是什么,非常便于 debug。

特點(diǎn)

(1) 使用字符串命名測(cè)試方法

在前面的例子中,我們可以看到測(cè)試的方法名是使用字符串來(lái)命名,不需要像 JUnit 一樣遵循 Java 方法的命名規(guī)則。這樣我們就不用糾結(jié)使用什么樣的命名方法,只需要像寫(xiě)一句話一樣來(lái)編寫(xiě)測(cè)試方法名稱。

(2) 語(yǔ)義化的結(jié)構(gòu)

在前面的例子中,我們看到了 block 的概念。它可以幫助我們更好的組織代碼結(jié)構(gòu),寫(xiě)出更加便于閱讀的代碼。其實(shí)在每一個(gè) block 聲明之后,我們還可以在添加一個(gè)字符串,達(dá)到注釋的作用。比如:

given: "a mars rover at position 1,2 and direction is north"

除了上面的例子里看到的,Spock 還提供了 cleanup 、 expect 、 where 這三個(gè) block。詳細(xì)信息可以看看它的??文檔??。

因?yàn)?Spock 強(qiáng)制要求使用 block 來(lái)組織測(cè)試代碼,這樣就可以強(qiáng)迫我們寫(xiě)出結(jié)構(gòu)化的代碼,更加便于閱讀。

(3) 使用 data table 構(gòu)造參數(shù)化測(cè)試

對(duì)于參數(shù)化測(cè)試,我們?cè)賮?lái)看一個(gè)例子。

def "should move mars rover from position 1,2 forward to #movedPosition.x,#movedPosition.y when direction is #direction and move length is #length"() { 
given:
def marsRover = MarsRoverFixture.buildMarsRover(
position: new Position(1, 2),
direction: direction,
)

when:
def movedMarsRover = marsRover.forward(length)

then:
movedMarsRover.position == movedPosition
movedMarsRover.direction == direction

where:
direction | length || movedPosition
Direction.EAST | 2 || new Position(3, 2)
Direction.WEST | 3 || new Position(-2, 2)
Direction.SOUTH | -1 || new Position(1, 3)
Direction.NORTH | 1 || new Position(1, 3)
}

我們可以看到代碼的最后一段是一個(gè) where block,這是 Spock 中用來(lái)定義數(shù)據(jù)測(cè)試的數(shù)據(jù)的地方。例子中的寫(xiě)法被稱作 data table。盡管 Spock 還支持一些其他的寫(xiě)法,但是我個(gè)人認(rèn)為 data table 是一個(gè)更加可讀的寫(xiě)法,所以這也是我最常使用的寫(xiě)法。并且這個(gè)寫(xiě)法不需要手動(dòng)調(diào)整格式,IDEA 支持自動(dòng) format,堪稱完美。

我們還可以留意一下方法名。方法名中有幾個(gè)以 # 開(kāi)頭的字符串,它們其實(shí)是在引用 data table 中定義的變量。這種通過(guò)變量名引用的方式可讀性遠(yuǎn)遠(yuǎn)大于 JUnit 的索引值的方式。并且我們可以看到 #movedPosition.x 這樣的表達(dá)式,它們可以直接使用這些對(duì)象中的字段值來(lái)生成方法名,不需要依賴于對(duì)象的 toString 方法。

對(duì)于斷言失敗的測(cè)試,同樣會(huì)像上面的例子一樣在測(cè)試輸出中打印具體的數(shù)據(jù),方便定位到測(cè)試失敗的用例。

與 JUnit 對(duì)比起來(lái),Spock 的 data table 既讓參數(shù)列表和測(cè)試方法放到了一起,又能支持任意類型的參數(shù),還可以沒(méi)有副作用地定義參數(shù)名稱,算是把 JUnit 參數(shù)化測(cè)試的痛點(diǎn)都解決了。

(4) 簡(jiǎn)潔的斷言

在上面的例子中,我們看到 Spock 的斷言十分簡(jiǎn)潔,不需要像使用 assertj 一樣寫(xiě)很長(zhǎng)的 assertThat(xxx).isEqualTo(yyy),只需要一個(gè)返回 boolean 的表達(dá)式就可以了。

甚至可以把多行斷言提取到一個(gè)方法中,返回他們與運(yùn)算的結(jié)果。

(5) 使用 Groovy 編寫(xiě)測(cè)試

使用 Groovy 來(lái)編寫(xiě)測(cè)試,可以說(shuō)既是優(yōu)點(diǎn),也是缺點(diǎn)。

優(yōu)點(diǎn)是在于 Groovy 是動(dòng)態(tài)語(yǔ)言,我們可以利用這一特性在測(cè)試中少寫(xiě)一些啰嗦的代碼。并且在前面的例子中,斷言里面獲取的 marsRover.position 字段本身是 private 字段,測(cè)試仍然可以正常執(zhí)行。這些都是由 Groovy 帶來(lái)的靈活性。

缺點(diǎn)在于這是一個(gè)相對(duì)小眾的語(yǔ)言。如果不是因?yàn)?Gradle,或許不會(huì)有多少人熟悉它的語(yǔ)法。這也會(huì)導(dǎo)致人們?cè)谶x擇它時(shí)會(huì)變得更加謹(jǐn)慎。

(6) 與 IDE 的完美集成

我一直使用的 IDEA 是能夠完美適配它的。除了前面提到的 format data table ,最主要的是 IDEA 能像執(zhí)行 JUnit 一樣執(zhí)行它,并且不需要任何的配置。

缺點(diǎn)

我在第一個(gè)項(xiàng)目里面使用 Spock 時(shí),幾乎沒(méi)有發(fā)現(xiàn)它有什么缺點(diǎn),以至于在后來(lái)的項(xiàng)目中總是在問(wèn) TL 能不能把它加到項(xiàng)目里來(lái)。

但是后來(lái)在一個(gè) Kotlin 項(xiàng)目中嘗試使用它時(shí),卻遇到一些問(wèn)題。

與 Kotlin 的集成問(wèn)題:

(1) 無(wú)法識(shí)別 Kotlin 的語(yǔ)法糖

Groovy 不能直接識(shí)別到 Kotlin 代碼中的各種語(yǔ)法糖,這就讓測(cè)試寫(xiě)起來(lái)有那么一點(diǎn)點(diǎn)不舒服。

比如命名參數(shù)。其實(shí) Groovy 也支持命名參數(shù),但是語(yǔ)法和 Kotlin 不同。這就顯得有一點(diǎn)尷尬。不過(guò)這個(gè)問(wèn)題可以通過(guò)為測(cè)試編寫(xiě)一些 fixutre 之類的代碼來(lái)幫助處理這里問(wèn)題。比如下面這個(gè) Kotlin 類型:

data class MarsRover(  
private val position: Position,
private val direction: Direction,
)

我們可以為它編寫(xiě)一個(gè) fixture,就能在測(cè)試?yán)锩嬉彩褂妹麉?shù)了:

class MarsRoverFixture {  
@NamedVariant
static MarsRover buildMarsRover(position, direction) {
new MarsRover(position, direction)
}
}

其他的一些語(yǔ)法問(wèn)題也基本都能繞過(guò),本質(zhì)思路就是把要測(cè)試的代碼想象成編譯后的 Java,這樣就能找到繞過(guò)的辦法。

(2) 沒(méi)有對(duì) final class 的 mock 支持

這是一個(gè)基本繞不過(guò)去的問(wèn)題。Kotlin 里面的類型默認(rèn)都是 final,不能再被繼承。但是 Spock 的 mock 卻需要為要 mock 的對(duì)象的類型創(chuàng)建一個(gè)子類。這就導(dǎo)致我們不能去 mock 那些類型。其實(shí)這個(gè)問(wèn)題不是 Spock 特有的,Mockito 也有這個(gè)問(wèn)題。只不過(guò)在使用 JUnit 時(shí)我們會(huì)選擇用 MockK 作為 Kotlin 項(xiàng)目的 mock 工具,而不是 Mockito。

解決這個(gè)問(wèn)題的策略有好幾個(gè):

  • 盡可能不去 mock。這要求我們?cè)O(shè)計(jì)出更容易測(cè)試的代碼,這樣就可以避免在測(cè)試中使用 mock。
  • 因?yàn)?Spring 組件需要被繼承,所以會(huì)使用 Kotlin All-open compiler 來(lái)為 Spring 提供支持,我們就可以 mock 這些 Spring Component

在寫(xiě)這篇文章的時(shí)候,發(fā)現(xiàn)一個(gè)很久沒(méi)有更新的倉(cāng)庫(kù) kotlin-test-runner,也許可以借鑒一下這里的思路來(lái)解決這個(gè)問(wèn)題。

(3) 與 JUnit 的兼容問(wèn)題

對(duì)于上一個(gè)問(wèn)題,我們當(dāng)時(shí)還有一個(gè) workaround,那就是使用 JUnit5 + MockK 來(lái)編寫(xiě)那些需要 mock 的測(cè)試。但是那個(gè)時(shí)候的 Kotlin 版本還比較低,沒(méi)有遇到和 JUnit 的兼容問(wèn)題。

兼容問(wèn)題是 JUnit 在編寫(xiě) Spring 集成測(cè)試的時(shí)候,如果有 mock bean 的需求,需要使用 springmock 里面的 @MockkBean 注解。但是從 kotlin 1.5.30 開(kāi)始,這個(gè)庫(kù)就不能和 Spock 編寫(xiě)的 Spring 集成測(cè)試兼容,會(huì)出現(xiàn) NPE 問(wèn)題。這個(gè)問(wèn)題在使用 Kotlin 對(duì) Specification 子類進(jìn)行反射時(shí)會(huì)出現(xiàn)。

這個(gè)問(wèn)題一直到 Kotlin 1.6.20-M1 才修復(fù)。

Groovy 語(yǔ)言的學(xué)習(xí)成本:

就像前面提到過(guò)的,使用 Groovy 還是有一些學(xué)習(xí)成本的。如果團(tuán)隊(duì)里沒(méi)有熟悉它的人,可能會(huì)走一點(diǎn)彎路。

使用 Kotest 作為測(cè)試框架

Kotest 是在無(wú)意中發(fā)現(xiàn)的測(cè)試框架,還沒(méi)有在實(shí)際的項(xiàng)目中實(shí)踐過(guò)。所以這里只能分享一下如何使用,沒(méi)有什么經(jīng)驗(yàn)分享。

如何使用 Kotest

我們來(lái)看一個(gè)例子:

class MarsRoverKotestTest : BehaviorSpec({  
given("a mars rover") {
val marsRover = MarsRover(
position = Position(1, 2),
direction = Direction.EAST,
)
`when`("it report information") {
val (position, direction) = marsRover.report()
then("get it's position and direction") {
position shouldBe Position(1, 2)
direction shouldBe Direction.EAST
}
}
}
})

這是一種 BDD 風(fēng)格的測(cè)試。Kotest 使用 BehaviorSpec 類封裝起來(lái)。

在 then 中,我們沒(méi)有看到常見(jiàn)的 assertThat() 語(yǔ)句,取而代之的是 Kotest 的 assertion 庫(kù)提供的方法。

特點(diǎn)

(1) 豐富的測(cè)試風(fēng)格支持

除了上面的例子,我們還有很多的測(cè)試風(fēng)格可以選擇,這在它的文檔中有介紹:??Testing Styles | Kotest??。

在這些風(fēng)格中,測(cè)試名稱都是通過(guò)字符串來(lái)編寫(xiě)的。如前面所說(shuō),這樣我們就不用像使用 JUnit 一樣糾結(jié)測(cè)試方法的命名風(fēng)格,只管描述測(cè)試目的就可以來(lái)。

然而除了 BDD 這種測(cè)試風(fēng)格外,其他的測(cè)試風(fēng)格都沒(méi)有對(duì)測(cè)試代碼的組織有任何強(qiáng)制要求。這就需要團(tuán)隊(duì)為測(cè)試代碼測(cè)組織達(dá)成一致并維護(hù)它。這和 JUnit 沒(méi)有什么區(qū)別。

(2) 對(duì) data driven test 的支持

Kotest 提供了擴(kuò)展來(lái)支持 data driven test。當(dāng)然,不使用這個(gè)擴(kuò)展也可以進(jìn)行,比如用 list 構(gòu)造好數(shù)據(jù)之后 foreach 創(chuàng)建測(cè)試。不過(guò)這里的例子我們還是使用這個(gè)擴(kuò)展來(lái)演示。

class MarsRoverKotestTest : FunSpec({  
context("data test") {
withData(
nameFn = { (direction, length, position) ->
"should move mars rover from 1,2 to ${position.x},${position.y} when direction is $direction and move length is $length"
},
Triple(Direction.EAST, 2, Position(3, 2)),
Triple(Direction.WEST, 3, Position(-2, 2)),
Triple(Direction.SOUTH, -1, Position(1, 3)),
Triple(Direction.NORTH, 1, Position(1, 3)),
) { (direction, length, movedPosition) ->
val marsRover = MarsRover(
position = Position(1, 2),
direction = direction,
)
val movedMarsRover = marsRover.forward(length)
movedMarsRover.report().position shouldBe movedPosition
movedMarsRover.report().direction shouldBe direction
}
}
})

雖然這個(gè) data driven test 相對(duì)于 Spock 的 data table 來(lái)講沒(méi)有那么直觀,但是對(duì)比 JUnit 的話,能夠方便的自定義測(cè)試方法名、支持任意類型的參數(shù)并且測(cè)試數(shù)據(jù)與測(cè)試代碼可以放在一起,已經(jīng)算是一個(gè)巨大的進(jìn)步了。

(3) 簡(jiǎn)潔的斷言

在上面的例子里面我們看到,Kotest 提供了自己的斷言庫(kù),不需要再寫(xiě)冗長(zhǎng)的 assertThat() 之類的語(yǔ)句。

(4) 使用 Kotlin 編寫(xiě),能與 Kotlin 項(xiàng)目完美結(jié)合

使用 Kotlin 來(lái)編寫(xiě)測(cè)試,可以使用到 Kotlin 里面的各種語(yǔ)法糖。這樣就不用像 Spock 一樣在語(yǔ)法切換中掙扎。

(5) 支持 MockK

同樣的,因?yàn)?Kotest 的測(cè)試使用 Kotlin 編寫(xiě),自然是支持 MockK 的。這樣就能利用 MockK 的特性,支持對(duì) final class 的 mock。

(6) 與 JUnit 兼容

因?yàn)?Kotest 是基于 JUnit 平臺(tái)的,所以是能和 JUnit 兼容的,不會(huì)出現(xiàn)上面的 Spock 那樣的問(wèn)題。

缺點(diǎn)

因?yàn)闆](méi)有在實(shí)際的項(xiàng)目中實(shí)踐過(guò),所以目前沒(méi)有發(fā)現(xiàn)很多的缺點(diǎn)。

(1) 與 IDEA 和 Gradle 的集成不夠完美

這個(gè)問(wèn)題的表現(xiàn)是在 IDEA 里面無(wú)法執(zhí)行單個(gè)測(cè)試方法。但是細(xì)究后發(fā)現(xiàn),實(shí)際上是和 gradle 的集成不夠好。

默認(rèn)情況下,IDEA 會(huì)使用 gradle 來(lái)執(zhí)行測(cè)試。執(zhí)行單個(gè)測(cè)試的命令是 gradle test --tests "xxx.Class.yyyMethod"。對(duì)于 JUnit,這里的 class 和 method 是很直觀的類名和方法名。但是 Kotest 的寫(xiě)法卻不是編寫(xiě)類里面的方法,而是調(diào)用方法生成測(cè)試。所以 gradle 的這個(gè)命令就沒(méi)有辦法生效,也就沒(méi)有辦法只執(zhí)行一個(gè)測(cè)試方法了。

在把 IDEA 的配置更新成使用 IDEA 來(lái)運(yùn)行測(cè)試后,在 mac 上能夠正常執(zhí)行單個(gè)測(cè)試方法。

不要使用 Spek

前面介紹了兩種值得一試的測(cè)試框架,這里再介紹一種不建議使用的框架。

當(dāng)初想要嘗試這個(gè)框架,是因?yàn)榭吹接芯W(wǎng)友說(shuō)這是 Kotlin 版本的 Spock 。但是實(shí)踐下來(lái)并沒(méi)有發(fā)現(xiàn)它有和 Spock 類似的功能,并且還出現(xiàn)了這些痛點(diǎn):

  • 與其他測(cè)試框架混合使用的問(wèn)題:當(dāng)與其他測(cè)試框架混合使用時(shí),Spek 測(cè)試總是會(huì)先執(zhí)行。哪怕我們?cè)?IDEA 里面只想執(zhí)行一個(gè) JUnit 的單元測(cè)試,Spek 也會(huì)先把自己的所有測(cè)試跑完,然后才會(huì)執(zhí)行到我們想要執(zhí)行的測(cè)試。這就意味著在 Speck 測(cè)試編寫(xiě)了很多之后,執(zhí)行其他測(cè)試就會(huì)等待很久。
  • 不能編寫(xiě) Spring 集成測(cè)試。
  • 我在寫(xiě) demo 的時(shí)候發(fā)現(xiàn),它的 IDEA 插件在 Windows 上面無(wú)法工作。

如果這些痛點(diǎn)你都能忍,那我也不建議使用這個(gè)框架,畢竟上面已經(jīng)有更好的選擇了。

總結(jié)

現(xiàn)在我們有了兩個(gè) JUnit 以外的測(cè)試框架選擇。當(dāng)然它們也不是完美的,JUnit 仍然是那個(gè)最穩(wěn)定、風(fēng)險(xiǎn)最低的那一個(gè)。但如果你想嘗試一下這兩個(gè)框架的話,可以考慮一下這些方面:

(1) 生產(chǎn)代碼的編程語(yǔ)言:

  • 如果是 Kotlin,那么可以考慮 Kotest,不要考慮 Spock
  • 如果是 Java,那么這兩個(gè)都值得考慮

(2) 語(yǔ)言熟悉程度:Kotlin 明顯是比 Groovy 更加流行,這個(gè)角度考慮的話 Kotest 是更優(yōu)的選擇

(3) 測(cè)試框架的流行程度(這方面我不知道有什么評(píng)價(jià)標(biāo)準(zhǔn),只是作為參考):

  • 兩個(gè)框架在 GitHub 上的 star 數(shù)量半斤八兩,一個(gè) 3.1k,一個(gè) 3.2k(JUnit 也才 4.9k)
  • 在 MVNRepository 上,Spock 的 usage 明顯高于 Kotest

(4) IDEA 的集成:

  • Spock 在這方面完全沒(méi)有問(wèn)題
  • Kotest 需要安裝插件,并且需要配置才能運(yùn)行單個(gè)測(cè)試

(5Gradle 集成:

  • Spock 完美集成
  • Kotest 不能執(zhí)行單個(gè)測(cè)試
責(zé)任編輯:趙寧寧 來(lái)源: Thoughtworks洞見(jiàn)
相關(guān)推薦

2017-01-14 23:42:49

單元測(cè)試框架軟件測(cè)試

2024-10-16 16:09:32

2009-06-01 10:47:32

jboss seam例jboss seam開(kāi)jboss seam

2023-12-24 10:00:35

Java單元測(cè)試

2009-08-19 09:00:48

單元測(cè)試框架自動(dòng)化測(cè)試

2010-08-27 09:11:27

Python單元測(cè)試

2023-07-26 08:58:45

Golang單元測(cè)試

2011-05-16 16:52:09

單元測(cè)試徹底測(cè)試

2017-01-16 12:12:29

單元測(cè)試JUnit

2017-01-14 23:26:17

單元測(cè)試JUnit測(cè)試

2022-04-27 08:17:07

OCMock單元測(cè)試集成

2011-06-14 15:56:42

單元測(cè)試

2020-08-18 08:10:02

單元測(cè)試Java

2024-04-26 11:14:34

C#單元測(cè)試框架

2017-03-23 16:02:10

Mock技術(shù)單元測(cè)試

2021-05-05 11:38:40

TestNGPowerMock單元測(cè)試

2020-05-07 17:30:49

開(kāi)發(fā)iOS技術(shù)

2011-07-04 18:16:42

單元測(cè)試

2011-06-14 15:39:46

單元測(cè)試

2012-05-21 09:41:54

XcodeiOS單元測(cè)試
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

大陆av在线播放| 日韩av电影在线免费播放| 免费黄色在线播放| 高潮在线视频| 中文在线资源观看网站视频免费不卡| 国产精品青草久久久久福利99| 亚洲一级理论片| 日韩三级久久| 在线影院国内精品| 国产成人一区二区三区别| 视频午夜在线| 国产精品一色哟哟哟| 2019最新中文字幕| 秋霞a级毛片在线看| 亚洲精品国产偷自在线观看| 亚洲大尺度美女在线| 欧美亚洲日本在线观看| 污污视频在线| 国产欧美日韩在线看| 99精彩视频| 中文字幕精品无码亚| 亚洲久久一区| 欧美成人免费播放| 国产精成人品免费观看| 国内精品偷拍| 日韩欧美综合在线| 孩娇小videos精品| 欧美黑人粗大| 黄色一区二区三区| 欧美黄色免费网址| 欧美一级二级三级区| 久久综合色鬼综合色| 成人av免费电影| 在线观看中文字幕av| 亚洲一区二区三区免费在线观看| 欧美精品在线观看91| 四季av中文字幕| 亚洲人成精品久久久 | 国产麻豆一精品一男同| 狂野欧美一区| 欧美一性一乱一交一视频| 久久久精品99| 欧美1区免费| 久久久精品美女| 99久久99久久精品免费看小说. | 精品丝袜一区二区三区| www.欧美com| 久久99精品久久久野外观看| 欧美丰满美乳xxx高潮www| 日本美女高潮视频| xxxxx.日韩| 欧美日韩国产一级片| 特级丰满少妇一级| 欧美网站免费| 欧美剧在线免费观看网站| 亚洲欧美自偷自拍另类| 精品三级在线| 9191久久久久久久久久久| www.99r| 日韩深夜福利网站| 欧美电影一区二区| 中文字幕第一页在线视频| 国产精品2区| 欧美一卡二卡在线观看| 极品人妻一区二区| www.国产精品一区| 亚洲国产精品成人av| 亚洲精品自在在线观看| 亚洲风情第一页| 国产黄色精品网站| 国产精品毛片va一区二区三区| 丰满人妻一区二区三区免费| 国产 欧美在线| 国产在线精品日韩| 户外极限露出调教在线视频| 久久久高清一区二区三区| 日韩精品不卡| 黄色免费在线观看网站| 一区二区久久久久久| 欧日韩免费视频| 中文字幕资源网在线观看免费 | 国产又色又爽又黄又免费| 久久99国产精品免费网站| 97人人干人人| 五月天婷婷社区| 中文字幕欧美三区| 加勒比海盗1在线观看免费国语版| 激情在线视频播放| 日韩欧美高清在线视频| 日本人69视频| 成人免费视频国产免费麻豆| 成人黄色a**站在线观看| 欧美高清视频一区| 男女性色大片免费观看一区二区 | 国产精欧美一区二区三区白种人| 国产欧美88| 日韩av在线免费播放| 久久久久亚洲AV成人无在| 91精品一区二区三区综合| 高清亚洲成在人网站天堂| 国产精华7777777| 国产电影精品久久禁18| 欧美日韩三区四区| 91在线中字| 日本高清不卡一区| 精人妻一区二区三区| 日本一本不卡| 91精品国产电影| 中文 欧美 日韩| 91在线观看视频| 亚洲成人动漫在线| 中文在线免费二区三区| 欧美成人一区二区三区| 黄色av片三级三级三级免费看| 亚洲无吗在线| 91精品一区二区| 精品久久av| 婷婷一区二区三区| 欧美体内she精高潮| 欧美日韩在线二区| 91精品国产成人www| 精品欧美在线观看| 亚洲欧洲三级电影| 中文字幕在线观看第三页| 美女福利一区| 欧美日本在线视频中文字字幕| 中文字幕人妻一区二区在线视频 | 51漫画成人app入口| 91超碰成人| 久久久免费精品视频| 在线观看毛片av| 久久亚洲捆绑美女| 亚洲国产成人精品无码区99| 国产精品1区| 神马久久久久久| 精品久久久久久久久久久国产字幕 | 丰满肉肉bbwwbbww| 一卡二卡三卡日韩欧美| 欧美午夜精品理论片| 91欧美日韩| 国产日韩亚洲欧美| 午夜精品一区| 欧美日韩免费不卡视频一区二区三区| 久久久久久九九九九九| 亚洲一区黄色| 久久青青草原| 伊人久久视频| 亚洲欧洲在线视频| 天天天天天天天干| 国产精品毛片久久久久久| 成年人在线观看视频免费| 欧美最新另类人妖| 国产精品免费视频xxxx| av在线免费观看网| 欧美日韩一二三区| 男人的午夜天堂| 九九**精品视频免费播放| 中文字幕免费在线不卡| www.欧美视频| 欧美大片大片在线播放| 国内爆初菊对白视频| 精品久久久久人成| 一区二区三区四区免费| 青青草国产成人av片免费| 一级特黄录像免费播放全99| 日韩国产91| 色综合久久88| 深爱激情五月婷婷| 91成人在线观看喷潮| 亚洲a∨无码无在线观看| 久久99精品久久久久久| 黄色片免费在线观看视频| 嫩草国产精品入口| 国产成人97精品免费看片| 91精品国产综合久久久久久豆腐| 欧美高清www午色夜在线视频| 国产盗摄x88av| 91在线播放网址| www.亚洲高清| 国产精品a久久久久| 蜜桃精品久久久久久久免费影院| 99riav视频一区二区| 欧美精品日韩三级| 涩涩视频在线观看免费| 欧美另类高清zo欧美| 日韩欧美激情视频| 国产精品天干天干在线综合| 丰满少妇xbxb毛片日本| 日韩av一二三| 欧美中日韩在线| 国产乱码精品一区二区三区四区| 91人人爽人人爽人人精88v| av电影免费在线看| www.日韩av.com| 五月激情丁香婷婷| 欧美精品电影在线播放| 日韩黄色在线播放| 亚洲精品一卡二卡| 精品人伦一区二区三电影| 国产高清不卡二三区| 日av中文字幕| 一区二区亚洲| 亚洲巨乳在线观看| 香蕉精品久久| 91久久精品国产91久久性色tv| 美女福利一区二区| 欧美激情视频网| av大全在线免费看| 亚洲风情亚aⅴ在线发布| 国产乱淫片视频| 在线观看免费亚洲| 国产又黄又粗又爽| 夜夜夜精品看看| 黄视频网站免费看| 国产三级三级三级精品8ⅰ区| 国产精品日日摸夜夜爽| 激情综合色综合久久| 超碰97人人射妻| 亚洲黄色影片| 日本成人在线不卡| 羞羞答答成人影院www| 日本10禁啪啪无遮挡免费一区二区| 一区三区自拍| 亚洲free嫩bbb| 成人亚洲免费| 国产精品jvid在线观看蜜臀| аⅴ资源天堂资源库在线| 欧美老女人性生活| 日本暖暖在线视频| 亚洲最新av在线| 久草在线网址| 亚洲欧美www| 三级黄视频在线观看| 亚洲国产天堂久久综合网| 性猛交xxxx乱大交孕妇印度| 69久久夜色精品国产69蝌蚪网| 波多野结衣视频免费观看| 日韩欧美国产一区二区| 在线观看亚洲欧美| 精品国产乱码久久久久久虫虫漫画| 精品无码m3u8在线观看| 亚洲一二三专区| www.youjizz.com亚洲| 亚洲第一精品在线| 日本少妇在线观看| 性做久久久久久久久| 久久精品美女视频| 亚洲va国产va欧美va观看| 日韩福利片在线观看| 午夜私人影院久久久久| 奇米影视第四色777| 欧美日韩一二三四五区| 在线观看国产亚洲| 色偷偷一区二区三区| 看黄色一级大片| 欧美精品日韩综合在线| 国产视频一区二区三| 欧美成人精品二区三区99精品| 亚洲精品免费在线观看视频| 日韩电影第一页| 国产视频第一区| 日韩视频免费看| 青草青在线视频| 欧美在线视频在线播放完整版免费观看| 正在播放日韩精品| 国产女精品视频网站免费| 人人爱人人干婷婷丁香亚洲| 国产精品一区二区免费看| 亚洲欧洲美洲国产香蕉| 亚洲人一区二区| 欧美jizzhd精品欧美巨大免费| 福利视频一二区| 日韩av一区二区在线影视| 伊人免费视频二| 99久久精品国产精品久久| 亚洲成人黄色av| 一区二区在线观看av| 在线天堂中文字幕| 欧美视频中文一区二区三区在线观看| 91精品在线视频观看| 亚洲精品在线观看视频| 国产一二三在线观看| 欧美成人在线网站| 亚洲女同av| 成人性生交xxxxx网站| 欧美三级电影在线| 在线视频不卡一区二区| 亚洲黄色一区| 久久久久久久久久一区| 99久久综合精品| 小泽玛利亚一区| 日韩欧美精品网站| a在线观看视频| 亚洲欧洲自拍偷拍| 蜜臀av在线| 国产精品日韩在线观看| 国产美女撒尿一区二区| 亚洲精品一区国产精品| 中文久久精品| 亚洲一区二区三区三州| 欧美激情一区二区三区在线| 国产无套粉嫩白浆内谢| 欧美日本高清视频在线观看| 日韩一级片免费看| 久久久成人精品视频| 日韩a**中文字幕| 国产精品久久7| 91精品91| 在线黄色免费观看| www亚洲一区| 久久精品视频8| 欧美一区二区在线视频| 黄色小视频在线免费观看| 欧美精品videossex88| 国产亚洲欧美日韩精品一区二区三区| 精品蜜桃传媒| 亚洲激情自拍| 欧美一区二区三区影院| 国产精品电影一区二区| 欧美男人亚洲天堂| 亚洲精品第一国产综合精品| 后进极品白嫩翘臀在线播放| 成人黄色免费在线观看| 欧美日韩国产免费观看视频| 欧洲av无码放荡人妇网站| 成人福利视频在线| 国产无码精品在线观看| 精品久久久久久久久久久久包黑料| 久久黄色美女电影| 国产日韩在线免费| 日韩欧美电影| 午夜激情av在线| 国产欧美一区二区在线| 无码人妻精品一区二区三区9厂| 亚洲国产精品成人av| 精品国产一区二区三区四区vr | 精品视频资源站| 香蕉久久一区二区三区| 久久久久中文字幕| 一区二区中文字幕在线观看| 大地资源网在线观看免费官网| 国产在线观看一区二区| 亚洲少妇xxx| 欧美区一区二区三区| 一级毛片视频在线| 成人黄色激情网| 欧美一区综合| aaa黄色大片| 性久久久久久久久| 人人妻人人澡人人爽久久av| 91高清视频在线免费观看| 久久人人爽人人爽人人片av不| 蜜臀av色欲a片无码精品一区 | 欧美人动与zoxxxx乱| 日韩三级影院| 91免费综合在线| 欧美精品一卡| 国模私拍在线观看| 欧美日韩亚洲一区二区三区| 国产中文字幕在线观看| 国产精品久久久av久久久| 91九色精品国产一区二区| 欧美国产日韩在线视频| 亚洲一级二级在线| 男人的天堂在线视频| 国产精品狼人色视频一区| 欧美超碰在线| 香蕉视频免费网站| 一本一本大道香蕉久在线精品 | 国产精品久久久久久亚洲伦| 国产一区二区三区四区视频| 美女视频黄免费的亚洲男人天堂| 一区二区三区在线免费看| 日本www在线播放| 中文字幕欧美日韩一区| 国产婷婷一区二区三区久久| 午夜精品久久久久久99热| 国产探花一区二区| 国产乱叫456| 亚洲www啪成人一区二区麻豆| 蜜桃视频在线观看网站| 成人国产精品一区二区| 亚洲激情在线| av片在线免费看| 亚洲电影天堂av| 激情欧美一区二区三区黑长吊| 国内自拍中文字幕| 久久久久久97三级| 国产www视频| 国产成人一区二区在线| 狠久久av成人天堂| 亚洲综合第一区| 亚洲加勒比久久88色综合| 国产亚洲精彩久久| koreanbj精品视频一区| 自拍偷拍国产精品| 国产黄在线观看免费观看不卡| av成人观看| 久久精品国产亚洲一区二区三区| 久久高清免费视频|