I would like to test the obtained result using Either. Let's assume I have a simple example without Either
@Test
fun `test arithmetic`() {
val simpleResult = 2 + 2
Assertions.assertEquals(4, simpleResult)
}
And now i have wrapped result:
@Test
fun `test arithmetic with either`() {
val result : Either<Nothing, Int> = (2 + 2).right()
Assertions.assertTrue(result.isRight())
result.map { Assertions.assertEquals(4, it) }
}
I suppose it looks a little bit ugly, because the last Assertions will not be executed if we got Either.Left instead of Either.Right
How can I test the result properly in functional style?
kotlintest provides a kotest-assertions-arrow module which can be used to test Arrow types.
It basically expose matchers for Either and other data type. Take a look at this.
@Test
fun `test arithmetic with either`() {
val result : Either<Nothing, Int> = (2 + 2).right()
result.shouldBeRight(4)
}
The implementations of Either are data classes on both sides so you can do something like:
check(result == 4.right())
Or can use something similar with any other assertion library that uses equals to assert equality.
You can create extension functions:
fun <L, R> Either<L, R>.assertIsLeft(): L {
return when (this) {
is Either.Left -> value
is Either.Right -> throw AssertionError("Expected Either.Left, but found Either.Right with value $value")
}
}
fun <L, R> Either<L, R>.assertIsRight(): R {
return when (this) {
is Either.Right -> value
is Either.Left -> throw AssertionError("Expected Either.Right, but found Either.Left with value $value")
}
}
fun <T: Any> T.assertEqualsTo(expected: T): Boolean {
return this == expected
}
With them you tests could look like these:
val resultRight : Either<Nothing, Int> = (2 + 2).right()
resultRight
.assertIsRight()
.assertEqualsTo(4)
val resultLeft: Either<RuntimeException, Nothing> = RuntimeException("Some exception cause").left()
resultLeft
.assertIsLeft()