古いプロジェクトの1つでは、JUnit、kotlin.test、AssertJからのアサートが積み上げられました。これは彼の唯一の問題ではありませんでした。それは通常、フョードルおじさんからの手紙として書かれており、それを止めて単一の形にする時間はありませんでした。そして今、この時が来ました。
記事には、主観的な基準に従ってどのアサートがより優れているかについてのミニリサーチが含まれます。最初は簡単なことをしたかった:コピーと貼り付けでオプションをすばやくリベットするために一連のテストを投入する。次に、一般的なテストデータを強調表示し、一部のチェックを自動化し、すべてがどのように行われたかを示します。結果は小さなロゼッタ石でした。この記事は、現実に合ったアサートのライブラリを選択するのに役立つ場合があります。
この記事では、テストフレームワーク、テストアプローチ、およびデータ検証へのいくつかのトリッキーなアプローチを比較しないことをすぐに予約します。簡単なアサートについて話します。
退屈な推論、私の試練の歴史、その他の詳細を読むのが面倒な場合は、比較結果に直接移動できます。
少し背景
Scala, — ScalaTest. , - , - .
Kotlin, - , , Kotest ( , ).
, , — . :
- Kotlin IntelliJ Idea. Scala- — . , ScalaTest , . IntelliJ
<Click to see difference>
, . , , IntelliJ Idea — Kotlin- - , ?
- .
1 != 2
, , "expected" "actual". " 100 , , ", , "… , , , ". , ? , — , , - . - .
assertEquals(expected, actual)
— , . , — /, " , , " ,contains
,includes
. — , . - . -
assertThat("Friendship").contains("end")
. - . - JUnit4, ,
ExpectedException
@Rule
. - () .
- .
- . — , . , : , , generic-, . -:
assertThat(generic<Boolean>(input)).isEqualTo(true)
.<Boolean>
. . - , . . ? — , , . - , equals. - .
, , , , , . , — , . , -, QA-.
, 5 , , — .
:
- ScalaTest — .
- JUnit 5 — Java-.
- kotlin.test — multiplatform . — JUnit, .
- AssertJ — . FestAssert, - .
- Kotest — KotlinTest, kotlin.test. , ScalaTest. 1-22 — scala.
- Truth — . , AssertJ.
- Hamrest — . valid4j.
- Strikt — AssertJ .
- Kluent — , JUnit ( — kotlin.test), Kotest. — , .
- Atrium — , AssertJ, . — ( maven/gradle).
- Expekt — Chai.js. : — 4 .
- AssertK — AssertJ, AssertK ( ).
- HamKrest — Hamrest, HamKrest ( Hamcrest ).
— , -.
, - , JUnit , , , , , . ScalaTest, : , , — . : ? , :). / , , .
: listOf(1,2,3)
? — -, — . , , : , . , .
type erasure. Reified inline-, .
assertThrows<T>{...}
, reified :
assertThrows(expectedClass){...}
. , kotlin.test Asserter: , . , ?:)
GitHub. ScalaTest , .
: 0 — , 0.5 — , 1 — . — 9 .
-, , . . , . , - , " " , " " . .
Kotest | ± | ± | + | + | + | + | + | - | 6.0 | |
Kluent | ± | ± | + | + | + | + | + | - | 6.0 | |
AssertJ | ± | + | ± | + | ± | + | + | ± | 6.0 | |
Truth | ± | + | + | + | - | + | + | - | 5.5 | |
Strikt | ± | ± | ± | + | + | + | + | - | 5.5 | |
ScalaTest | ± | ± | ± | + | + | + | + | - | 5.5 | |
HamKrest | ± | - | ± | + | + | ± | + | - | 5.5 | |
AssertK | ± | ± | ± | + | ± | + | + | - | 5.0 | |
Atrium | ± | ± | ± | + | + | ± | + | - | 5.0 | |
Hamrest | ± | ± | ± | + | - | ± | + | - | 5.0 | |
JUnit | + | + | - | ± | + | - | ± | - | 4.5 | |
kotlin.test | + | ± | - | - | + | - | - | - | 3.5 | |
Expekt | ± | ± | - | + | - | ± | + | - | 3.5 |
:
-
"hello".shouldBeEqualTo("hello")
,"hello" `should be equal to` "hello"
. DSL . - :
invoking { block() } shouldThrow expectedClass.kotlin withMessage expectedMessage
- , , .
Expected Iterable to contain none of "[1, 3]"
— , Iterable . - :
<Click to see difference>
. - : .
— … ,
containsExactly
, —hasSameElementsAs
, —.usingRecursiveComparison().isEqualTo
.
:
<Click to see difference>
.
: - , . , , .
:
.usingRecursiveComparison()
, . : , , . , , ,
assertThat(actual) .usingRecursiveComparison() .isNotEqualTo(unexpected)
: .
: . , DSL.
- , .
- : , ,
assertThrows
JUnit5. , JUnit , ? - : , , :
containsAtLeastElementsIn
. ,assertThat(actual).isEqualTo(expected)
. - :
<Click to see difference>
. - : .
- : , .
- " ":
expected: 1 but was : 2 at asserts.truth.TruthAsserts.simpleAssert(TruthAsserts.kt:10) at common.FailedAssertsTestBase.simple assert should have descriptive message(FailedAssertsTestBase.kt:20) at [[Reflective call: 4 frames collapsed (https://goo.gl/aH3UyP)]].(:0) at [[Testing framework: 27 frames collapsed (https://goo.gl/aH3UyP)]].(:0) at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) at [[Testing framework: 9 frames collapsed (https://goo.gl/aH3UyP)]].(:0) at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) at [[Testing framework: 9 frames collapsed (https://goo.gl/aH3UyP)]].(:0) at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) at [[Testing framework: 17 frames collapsed (https://goo.gl/aH3UyP)]].(:0) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99) ...
, reified, : .
:
expectThat(haystack).not().contains(needle)
,expectThat(collection).doesNotContain(items)
.
:
contentEquals
. :expectThat(actual).not().contentEquals(unexpected)
. , ,Array<T>
Strikt - . —containsExactly
, —containsExactlyInAnyOrder
.
: . , . :
val actual: Array<String> = arrayOf("1") val expected: Array<String> = arrayOf("2") expectThat(actual).contentEquals(expected)
,
contentEquals
. ,contentEquals
:
infix fun <T> Assertion.Builder<Array<out T>>.contentEquals(other: Array<out T>)
-
val actual: Array<out String> = arrayOf("1") val expected: Array<String> = arrayOf("2") expectThat(actual).contentEquals(expected)
:
<Click to see difference>
.
: , .
: .
- , , . — , .
- , Hamcrest, - : -.
- — :
assertThat( { block() }, throws(has(RuntimeException::message, equalTo(expectedMessage))))
- : . - 3,5 . :
assertThat(collection, allOf(items.map { hasElement(it) }))
. - .
- : .
- :
<Click to see difference>
. - — - :
expected: a value that not contains 1 or contains 3 but contains 1 or contains 3
— AssertJ. ( , -).
: AssertJ
assertThat(collection).containsAll(items)
, AssertK ,containsAll
vararg
. ,containsAll(1,2,3)
, . , , — . — . ,containsOnly
containsExactly
.
:
<Click to see difference>
.
: - , , .
:
.usingRecursiveComparison()
.
— ( ), :
expected to contain exactly:<[3, 4, 5]> but was:<[1, 2, 3]> at index:0 unexpected:<1> at index:1 unexpected:<2> at index:1 expected:<4> at index:2 expected:<5>
?
: .
- : fluent infix.
assertThat(x).isEqualTo(y)
x shouldBe y
, ,expect(x).toBe(y)
expect(x) toBe y
. , , "". -o
:expect(x) contains o atLeast 1 butAtMost 2 value "hello"
. , , . infix- ( - ), Atrium fluent-. - : :
notToBe
,containsNot
. . , :contains
vararg
,containsElementsOf
, . ,contains(1,2,3)
, .expect(collection).containsNot.elementsOf(items)
. - ,
toList
. - , reified, : .
- : .
- :
<Click to see difference>
. - : ( , ), :
expected that subject: [4, 2, 1] (java.util.Arrays.ArrayList <938196491>) ◆ does not contain: ⚬ an entry which is: 1 (kotlin.Int <211381230>) ✘ number of such entries: 1 is: 0 (kotlin.Int <1934798916>) has at least one element: true is: true
- : .
: (
assertThat(actual, `is`(not(unexpected)))
assertThat(actual, not(unexpected))
containsString
vscontains
vshasItem
vshasItems
. , :hasItems
vararg
,Set<T>
T
. ,hasItems(1,2,3)
, .
assertThat(collection, allOf(items.map { hasItem(it) }))
:
assertThat(collection, not(anyOf(items.map { hasItem(it) })))
hasItems
, ± "", , .
: .
:
<Click to see difference>
.
: .
: .
- : -
assertEquals(expected, actual)
, :assertArrayEquals
,assertIterableEquals
.. - : , JUnit - , .
- :
assertLinesMatch(listOf(".*$needle.*"), listOf(haystack))
, . - :
assertLinesMatch
, ,assertIterableEquals
. - : ,
assertIterableEquals
Map
Set
, . - : .
- . JUnit, . , .
- , JUnit, :
- .
-
assertIterableEquals
, . - : JUnit'
assertEquals
, kotlin.test , . - : .
Kotest, Kluent AssertJ. , Kotlin , AssertJ ( ). , .
— , , AssertJ. , , .