oolong-kt / oolong

MVU for Kotlin Multiplatform
http://oolong-kt.org
Apache License 2.0
300 stars 14 forks source link

Unit Test Documentation #99

Open WendyYanto opened 4 years ago

WendyYanto commented 4 years ago

Is there any way to unit test update ? If there's a way, is there any documentation ? Thank you

pardom commented 4 years ago

Testing init, update, and view is as simple as calling those functions and asserting on the result. There's nothing to help with effect testing in the library yet, however, it might eventually look something like this:

class EffectAsserter<Msg : Any> {

    private val calls: MutableList<Msg> = mutableListOf()
    private val dispatch: Dispatch<Msg> = { msg -> calls.add(msg) }

    fun run(effect: Effect<Msg>) =
        apply { runBlocking { effect(dispatch) } }

    fun assertEquals(msgs: Iterable<Msg>) =
        apply { assertEquals(msgs, calls) }

    fun assertCount(count: Int) =
        apply { assertEquals(count, calls.size) }

}

@Test
fun `effect test`() {
    val (_, effect) = update(msg, model)
    EffectAsserter<Msg>()
        .run(effect)
        .assertCount(1)
        .assertEquals(listOf(Msg.Foo))
}

I've added this issue to the Documentation Project.

jcornaz commented 4 years ago

Personally I create the following simple helpers:


fun <Msg> Effect<Msg>.asFlow(): Flow<Msg> =
    channelFlow<Msg> { this@asFlow { sendBlocking(it) } }

suspend fun <Msg> Effect<Msg>.perform(): List<Msg> =
    asFlow().toList()

And then in my tests I use it like this:

val (_, effect) = update(msg, model)

// Perform the effect and return the list of dispatched messages
val messages: List<Msg> = runBLocking { effect.perform() }

// assert using my favoring assertion library
messages.shouldBeEmpty()
pardom commented 4 years ago

Follow up: I would recommend using TestCoroutineDispatcher so you can advance time like this https://github.com/oolong-kt/oolong/blob/main/oolong/src/jvmTest/kotlin/oolong/effect/EffectTest.kt#L48