…from Kotest
Keep your structure and assertions🔗
Like Kotest, TestBalloon is DSL-based and offers a choice of assertion libraries:
-
You can possibly keep large parts of your test structure by using some helper functions which translate from one of Kotest's test styles to TestBalloon's
testSuiteandtestDSL functions.Tip
TestBalloon Addons by A-SIT Plus is a ready-to-use library which provides a translation for
FreeSpec, plus replacements for Kotest's data-driven and property test functions. -
You can keep your assertion library (if it is Kotest Assertions, TestBalloon has an integration for it).
What needs to change🔗
Specs🔗
Kotest's specs become TestBalloon's top-level test suites:
Isolation Modes🔗
You can keep all code in Kotest's default Single Instance mode.
For Kotest's InstancePerRoot and InstancePerLeaf isolation modes, keep tests as they are, but wrap them into a test-level fixture:
class IsolatedTests : FunSpec({
isolationMode = IsolationMode.InstancePerLeaf // (1)!
val id = UUID.randomUUID() // (2)!
init {
test("one") {
println(id) // (3)!
}
test("two") {
println(id) // (4)!
}
}
})
- Kotest 6 deprecates
InstancePerLeafin favor ofInstancePerRoot, but the latter isolates only one level of tests. - The test context is initialized by re-creating the spec from its class via reflection (JVM-only).
- Each test prints a different ID.
- Each test prints a different ID.
val IsolatedTests by testSuite {
testFixture {
Uuid.random() // (1)!
} asParameterForEach { // (2)!
test("one") { uuid ->
println(uuid) // (3)!
}
test("two") { uuid ->
println(uuid) // (4)!
}
}
}
- The fixture's value can be any Kotlin type. You can also use an object expression with multiple properties.
- This test-level fixture provides a fresh, isolated parameter for each test.
- Each test prints a different ID.
- Each test prints a different ID.
Note
When migrating existing code, please remember the concepts of Green code and blue code and TestBalloon's golden rule.
Tip
Sharing state via TestBalloon's suite-level fixtures may help you squeeze complexity out of existing code, which did not have access to this mechanism.
Lifecycle Hooks🔗
Replace Kotest's lifecycle hooks with TestBalloon's wrappers, like in this re-use example:
fun TestConfig.printStart() = aroundEachTest { testAction ->
println("Starting a test $this")
testAction() // (1)!
}
val LifecycleHookTests by testSuite(testConfig = TestConfig.printStart()) {
test("this test should be alive") {
println("Johnny5 is alive!")
}
}
- You can put extra code after the test action, or surround it with a timeout function, or a try-catch, or…
Kotest has 44 mechanisms to track and influence tests:
- 14 "lifecycle hooks",
- 14 "simple extensions", and
- 16 "advanced extensions".
TestBalloon's TestConfig builder provides 4 functional mechanisms which achieve the same:
- two universal functions:
aroundEach()andtraversal(), - two convenience variants:
aroundAll()andaroundEachTest().
Note
TestBalloon's TestConfig wrappers can be combined and attached to any point in the test element hierarchy. TestConfig is a unified and composable mechanism, available for all kinds of test elements. Like the Modifiers of Jetpack Compose, this design make the API concise and flexible.
Extensions🔗
Data-driven testing🔗
TestBalloon uses plain Kotlin for data driven tests. There is no additional API to learn.
If you want to keep using Kotest's data-driven testing features, or its property testing, the TestBalloon Addons library by A-SIT Plus provides both.