A question about performance of Kotest asserters (...
# kotest
k
A question about performance of Kotest asserters (🧵)...
👀 1
This is the function under test:
fun factors(number: Long): Sequence<Long>
. It doesn't matter what it does, just that it takes a certain amount of time to run when given a large value. The following completes in 9 seconds:
Copy code
fun main() {
    measureTime {
        for (i in sequenceOf(2L..100_000L, 1_900_000L..2_000_000L, 100_000_900_000L..100_001_000_000L).flatten()) {
            val factors = factors(i).toList()
            check(factors.isNotEmpty()) { "$i -> $factors" }
            check(1 !in factors)
            check(factors.sorted() == factors)
            check(factors.reduce { a, b -> a * b } == i)
        }
    }.also {
        println("All checks passed. Elapsed time: $it")
    }
}
On the other hand, the following takes more than 1 minute:
Copy code
class PrimesTest : FreeSpec({
    "factors() tests" {
        for (i in sequenceOf(2L..100_000L, 1_900_000L..2_000_000L, 100_000_900_000L..100_001_000_000L).flatten()) {
            val factors = factors(i).toList()
            withClue({ "$i -> $factors" }) {
                factors.shouldNotBeEmpty()
                factors shouldNotContain 1
                factors.shouldBeSorted()
                factors.reduce { a, b -> a * b } shouldBe i
            }
        }
    }
})
Why is Kotest so much slower?
e
Looks like the culprit is
shouldNotContain
, mostly because the negated matcher relies on the regular matcher failing, and in doing so it produces a failure with type information which seems a bit costly
I did some work on making the failure message lazy, so we only evaluate it when wanted (i.e never for negated matchers). https://github.com/kotest/kotest/pull/4048 Sadly, life caught up before I managed to finish that up. I still think it's worth pursuing though
thank you color 1