Kotlin Assertion Libraries - Kluent

Kotlin Assertions Kluent
— Introduction — AssertJ — Strikt — AssertK — KoTest Assertions — Atrium — Kluent — Conclusion —
Looking at Kluent
The library Kluent markets itself as “Fluent Assertion Library for Kotlin“. In short it provides fluency and infix notations. However it has a hard dependency on Junit4 to make error assertions work properly. Additionally kotlin-test comes as a compile dependency.
Installation
Similarly to many other 3rd party libraries it is sufficent to add the dependency for Kluent. The current version is not directly obvious from the github repository. Therefore it can only be determined by looking into Maven Central or reading the CHANGELOG.md.
Gradle:
1 2 3 4 5 6 7 |
repositories { mavenCentral() } dependencies { testImplementation("org.amshove.kluent:kluent:1.68") } |
Maven:
1 2 3 4 5 |
<dependency> <groupId>org.amshove.kluent</groupId> <artifactId>kluent</artifactId> <version>1.68</version> </dependency> |
Syntax and Error messages
With Kluent you get the option for fluent or infix usage and provides backtick versions. Autocompletion always starts with should.
1 2 3 |
"PerfectFlow".shouldBeEqualTo("PerfectFlow") "PerfectFlow" shouldBeEqualTo "PerfectFlow" "PerfectFlow" `should not be equal to` "FlowPerfect" |
Fluent Style
The fluent interface acts comparable to AssertJ’s and allows the chaining of assertions. It will fail the test fast on the first error in the chain. Important to note is the constraint on the asserted type. E.g you can’t check the length of the String.
1 2 3 4 5 |
"PerfectFlow".shouldStartWith("Perf") .shouldEndWith("Flow") .shouldContain("ectFlo") .shouldNotStartWith("Flow") .shouldNotBeBlank() |
Softassertions
Softassertions in Kluent have the same general style as AssertJ.
1 2 3 4 5 6 7 |
assertSoftly { "PerfectFlow".shouldStartWith("Perf") .shouldEndWith("Flow") .shouldContain("the") .shouldNotStartWith("Flow") .shouldBeBlank() } |
Corresponding error message
1 2 3 4 5 |
org.amshove.kluent.MultiAssertionError: The following 2 assertions failed: 1) Expected the CharSequence PerfectFlow to contain the at asserts.KluentAssertions.stringAsserts(KluentAssertions.kt:21) 2) Expected the CharSequence to be blank, but was PerfectFlow at asserts.KluentAssertions.stringAsserts(KluentAssertions.kt:23) |
This implementation wins over the Kotlin variant of AssertJ SoftAssertions.
Assertion of Exceptions
Kluents syntax for exception assertion is quite descriptive. It uses invoking and coInvoking as keywords. The latter is support for suspend functions.
1 2 3 |
invoking { throw IllegalArgumentException() } shouldThrow IllegalArgumentException::class withMessage "Error XYZ" coInvoking { aSuspendingFun() } shouldThrow SuspendException::class withMessage "SuspendError" |
Equality vs Equivalency
With the shouldBeEqualTo objects will be compared by hashCode/equals like usual. Kluent offers additional ways to compare objects. Comparable to AssertJs field comparisons the shouldBeEquivalentTo compares two objects by their properties. This also works for collections.
1 2 3 4 5 6 7 8 9 10 |
data class Flow(val name: String, val cos: Double, val sin: Int) val f1 = Flow("Perfect", 1.0, 10) val f2 = Flow("Flow", 1.0, 10) f1.shouldBeEquivalentTo(f2) { it.excluding(Flow::name) } val perfectFlow = listOf(f1, f2) val flawedFlow = listOf(Flow("Flawed", 1.0, 10), Flow("Flow", 1.0, 10)) perfectFlow.shouldNotBeEquivalentTo(flawedFlow) { it.including(Flow::name) } perfectFlow.shouldBeEquivalentTo(flawedFlow) { it.excluding(Flow::name) } |
Additionally there are several helper functions which allow you to configure how you want to compare. For example in-/excluding, ordering and recursion. Unfortunately this feature comes with the caveat of being @Opt(ExperimentalStdlibApi::class).
Nullability and Narrowing
There is no inherent narrowing supplied by Kluent. The only available narrowing is the casting from nullable objects to the non-nullabe types.
That means for a nullable types we have to narrow it down to the actual type before we can verify specifically against the underlying type, but it is still possible to assert e.g. String? against String?.
1 2 3 |
var nullableStr: String? = null nullableStr.shouldNotBeNull().shouldContain("Perfect") nullableStr.shouldContain("Perfect") //Compile Error |
Supported Types and Diversity of Assertions
With Kluent you get mostly the basic assertions. It covers general basics, numericals, charsequence and collections. Additionally it supports some asserts for java.time.LocalDate/LocalTime/LocalDateTime as well as java.io.File.
Custom Assertions
There is a generic should function by which Kluent allows you to define you own assertions.
1 2 3 4 |
infix fun Optional.shouldContain(content: T) = this.should("Optional should contain $content") { this.isPresent && this.get() == content } Optional.empty().shouldBeEmpty() |
You can either return false or throw an exception to fail the assertion.
Of Note
Kluent also wrapped MockitoKotlin until version 1.64 but dropped it since then. If you like a wrapper for mockitokotlin2 you can use the old Mocking.kt and MockingBacktick.kt files as reference (Open Source Licensing applies).
Active Development
The last release was in July 2021. At the time of writing there are 12 Issues and 4 open PRs. Considering the library aims to simply provide basic fluent assertion support there are not as many possible additional useful functionalities.
Quality of Documentation
The documentation is not really fancy but covers examples for every functionality. Unfortunately the version and build status are outdated. You have to actively search for the current version and the Changelog.
— Introduction — AssertJ — Strikt — AssertK — KoTest Assertions — Atrium — Kluent — Conclusion —
Recent posts






Comment article