I wrote an article on test frameworks in the Kotli...
# feed
c
I wrote an article on test frameworks in the Kotlin ecosystem: https://ivan.canet.dev/blog/2025/06/17/state-of-kotlin-tests.html
👍🏾 1
K 19
👍 1
❤️ 3
p
Very nice 👍
h
I think you're underestimating just how many extensions are available for JUnit 5. For example, contrary to the table in your post, there is a Testcontainers integration – it's just not offered by the JUnit team, but by the Testcontainers team instead.
3
c
That's true. I hesitated to mention it or not (same for MockServer etc) because they do exist, but they're not really part of the framework
Maybe I should put 'Third party' in those slots
h
Also, kotlin-test uses expect/actual to integrate with JUnit 4/5 etc., so on JVM, you can use kotlin-test with JUnit 5 parameterized tests.
c
That's true. In most cases I didn't mention it because the only reason reason to use kotlin-test is for multiplatform support, and this doesn't allow multiplatform support.
h
Yeah, that’s also true.
c
The article will update in a few minutes with a few changes
If there are other frameworks that you often need to integrate with, don't hesitate to mention them and I'll add them to the list
v
Copy code
var UserTest by testSuite {
   ...
}
Is there any specific reason to use
var
instead of
val
in this example?
c
No, it should be
val
.
var
won't even compile—thanks for noticing!
👍 1
o
TestBalloon 🎈 author here. Some remarks from my perspective on this excellent article: The "WASM" spelling will upset @bashor 😉. Please 🙏 use "Wasm" instead.
TestBalloon is able to run its own tests on most platforms
Actually, starting with 0.3.2, TestBalloon supports all Kotlin targets (with CI tests on all tiers). Unfortunately, the 0.3.2 release process was defective. Now I'm waiting for Maven Central support to help me publish a new set of releases, which is currently stuck with the publication status changing from "VALIDATED" to "FAILED" without giving a reason. 😖 Tags: • TestBallon has compartments, which I consider a better alternative to tags for major use cases, as they bundle in a tailored configuration. Compartments for specific use cases (
UI
,
Concurrent
,
RealTime
) come with a (hopefully) well-designed out-of-the-box implementation. • Otherwise, tags would be a good example to demonstrate TestBalloon's extensibility, giving users the freedom to initialize tags by a mechanism of their choice:
Copy code
package com.example.testLibrary

import de.infix.testBalloon.framework.TestAction
import de.infix.testBalloon.framework.TestConfig
import de.infix.testBalloon.framework.TestSuite
import de.infix.testBalloon.framework.disable

enum class Tag(val enabled: Boolean = true) {
    SLOW,
    FAST,
    TOO_FAST(enabled = false) // <- or use a mechanism of your choice to initialize this, e.g. via Gradle properties
}

fun TestSuite.test(name: String, tags: Set<Tag>, action: TestAction) {
    test("$name ($tags)", testConfig = TestConfig.tagDependent(tags)) {
        action()
    }
}

fun TestConfig.tagDependent(tags: Set<Tag>) = if (tags.all { it.enabled }) TestConfig else disable()
Skipping tests: TestBallon provides an example which documents skipped tests so that these won't be forgotten accidentally. Your coverage of JUnit5 parameterization hell is excellent! Fixtures: Can you point me to use cases for isolated (non-shared) fixtures? I'd love to learn more about those. Also, what's the use case for declaring a fixture outside a test suite? Coroutines with `runTest`:
TestBalloon supports them but they are disabled by default (enable with TestConfig.testScope).
That seems to be incorrect: TestBalloon uses `runTest`'s `TestScope` by default. Other integrations (randomness, files): A primary goal of TestBalloon is to provide extensibility by composition. TestBallon currently provides just two integrations, which are also intended to serve as examples for creating your own extensions. I wonder what other integrations might preferably come pre-packaged, and which ones would be better left to the framework's user, avoiding unnecessary (micro-)dependencies and feature creep. Again, an excellent article. Thank you for making the effort to write this up!
😁 1
🫣 1
c
urh, fixed the Wasm casing 😅
You may want to retry the Central publication, I've seen people saying it was down earlier today. I haven't followed the story though, and I don't remember where I saw it
Can you point me to use cases for isolated (non-shared) fixtures?
Interestingly, that's kind of a hard question for me, because I basically never use shared fixtures. I think the best example I have is here: •
gradle.dir
is a fixture that refers to a temporary directory dedicated to this test. It is declared globally. • by creating a new prepared value
properties
that refers to
gradle.dir / "gradle.properties"
, I know that it will refer to specifically the config for that test. It is declared in the suite, but could very well be declared globally. Because each test gets its own instance of all prepared values, and thus their own temporary directory, it's safe to run all of these tests in parallel even though they use the same fixtures
Similarly, to test the KtMongo library, there is a single global fixture `testCollection` that generates a unique collection for specifically that test, including dropping the collection after the test if it is successful, and dumping the collection to the standard output if the test fails. All tests anywhere can simply use this method to get their own collection, with all the finalizers already set up.
Thanks for the feedback! I fixed the mistakes you spotted. About compartments: I need to figure out where to make them fit inside the blog post… It's already quite a big longer than what I'd like, but they are an interesting feature to mention. About integrations: my goal in this section was mostly to shine a light on Kotest because the rest of the article tends to often point Kotest flaws (which is inherent to the discussion since most of my design decisions in Prepared were specifically to avoid these flaws), but I wanted to end on a good note because I do have a lot of respect for what the Kotest team & contributors have achieved. When—if?—TestBalloon gets these kinds of framework integrations, don't hesitate to ping me to update the article.
o
I had an interaction with Maven Central support. They were pretty responsive, coming back after 2 hours with "You have run afoul of a previously unknown bug. It is a problem on our side, not yours.", then 4 about hours later they said they've fixed the issue. Re-publication is on its way.
🙏 1
same 1
I fully understand you appreciating the effort that has gone into Kotest and its integrations. They are valuable. Also, we're all (as always) standing on the shoulders of giants and Kotest is certainly a milestone towards better Kotlin testing. The question what to integrate into a framework and what to deliberately not integrate is not unique to Kotest, but will always remain relevant for any framework: • The more you integrate, the more you need to move for every new release, which can stall the process and make you fall behind other moving parts of the evolving Kotlin ecosystem. • Users have to learn which integrations exist and make their own fit-gap analysis when deciding whether to use them. Sometimes you can find yourself a considerable way down a rabbit hole before detecting that an integration is not for you. • A user-friendly API to extend a framework can tackle both problems, be more efficient, and provide the user with more control over how their testing setup works. So let's see how this plays out, which scenarios call for a larger integration, and which ones can be solved by creating or copy-pasting a few lines of framework-extension code.
💯 1
Update: TestBalloon 0.3.3-K2.1.21 is now available on Maven Central. Artifacts for other Kotlin versions upcoming.
m
That article led me to give TestBaloon a star 🙂
1
c
@Oliver.O 100% agree. None of the Prepared integrations have access to any internals or are built-into the framework itself. Anyone could have the exact same code in their own repository and they would be just as good. The only reason they're first-party is because I think that makes it convenient for users because they know they won't have version conflicts. I definitely agree that the framework should be extensible so that extensions can live anywhere—actually, I think that's a green flag towards the framework's longevity.