Does Kotest have the equivalent of AssertJ's `extr...
# kotest
k
Does Kotest have the equivalent of AssertJ's
extracting
feature? For example, in AssertJ I can do this:
Copy code
assertThat(foo)
    .extracting(Foo::id, Foo::description)
    .containsExactly(1234, "this is a foo")
The closest I could find was
shouldBeEqualUsingFields
but that's not suitable, as it requires another Foo argument which I can't easily construct; I only have the naked property values.
j
I'd do:
Copy code
all(foo) {
  it.id shouldBe 1234
  it.description shouldBe "stuff"
}
l
I'd go with
Copy code
assertSoftly(foo) {
    it.id shouldBe 1234
    it.description shouldBe "stuff"
}
This way you'd get every failing assertion
j
Yeah all ~= assertSoftly
K 2
e
Agree,, but you don't need to use
it
iirc? the assertSoftly should lambda should already be scoped to the subject?
j
Yeah I couldn't remember if all was
T.() -> Unit
or
(T) -> Unit
🤪
😂 1
It might even be
T.(T)
I've seen that here and there
e
Funny, yeah it seems to be
Copy code
test("hello") {
         val p = Point(0.0, 3.0)
         assertSoftly(p) {
            x shouldBeGreaterThan -1.0
            it.y shouldBe 3.0
         }
      }
👍 1
j
I like both, since you have access to the lambda arg you can destructure a pair or something with a useful name
s
(T).T -> is a bizarre signature lol
😛 1
e
good point @Jim 🙂
k
Yes, you can do that, but then the assertion failure message is something like "expecting 123 to be 456". The advantage of AssertJ's
extracting
method is that it tells you "expecting id to be 456 but was 123." Much clearer and much more helpful.
🤔 2
j
Maybe a reflection powered assertion could get us there with an auto clue
l
(T).T -> is a bizarre signature lol
"I want T both as a receiver and as a parameter". The only way to do it really is crying before, hence the T_T
e
Copy code
assertProperties(p) {
  Point::x shouldBe 0.0
  Point::y shouldBe 3.0
}
doable? @Jim? 🙂
j
I think I did something like this at work, let me see
s
We should add a compiler plugin that is better with shouldBe
so
x shouldBe y
can capture the variable name on the left
There's power assert, which is cool because it builds a tree of the intermediate values, but I think we could get half way there with something quicker that just captures the variable names, which is mostly what I want to see.
j
Copy code
fun isOdd(x: Int) = x % 2 != 0

data class IntWrapper(val value: Int) {
    fun isOddWrapper() = isOdd(value)
}

class SampleTests : FunSpec({
    test("function pointer") {
        all(IntWrapper(1)) {
            its { ::isOddWrapper } shouldBe false
            its { ::isOdd } shouldBe false
        }
    }
})

data class ShouldBeLeft<R>(val name: String, val actual: R) {
    infix fun shouldBe(expected: R) {
        withClue("Expected property $name to equal $expected but was $actual") {
            actual shouldBe expected
        }
    }
}

infix fun <T, R> T.its(kfunc: (T) -> KFunction<R>): ShouldBeLeft<R> {
    val f = kfunc(this)

    return if ((f as? FunctionReferenceImpl)?.boundReceiver != null) {
        ShouldBeLeft(f.name, f.call())
    } else {
        ShouldBeLeft(f.name, f.call(this))
    }
}
damn, too slow 😂
Copy code
Expected property isOddWrapper to equal false but was true
java.lang.AssertionError: Expected property isOddWrapper to equal false but was true
expected:<false> but was:<true>
only works with JVM I think though
355 Views