google/truth

asserts should support kotlin coroutines support.

hs-kdhillon opened this issue · 6 comments

I am trying to test network connectivity and by method is a suspend function. It work be nice if there is coroutine support present like mockito provides, for example, coAssertThat().

Currently, we need to wrap the assert call inside runBlocking{} scope.
runBlocking { assertThat(mockNetworkInfo.isConnected()) }

it would be nice if this support is provided so that all we need to do is:
coAssertThat(mockNetworkInfo.isConnected())

That is impossible as the isConnected() call executes in the context of the enclosing function body not inside assertThat. assertThat is just receiving a boolean. This is an entirely orthogonal problem to the assertion library. What you want is like @Test suspend fun foo() {} which is tracked at https://youtrack.jetbrains.com/issue/KT-22228.

runBlocking {
    val result = repository.getConcreteNumberTrivia(number)
    coVerify { mockRemoteDataSource.getConcreteNumberTrivia(number) }
    assertThat(result).isEqualTo(Success(entity))
}

Here the only suspending function is

val result = repository.getConcreteNumberTrivia(number)

And the only thing i am interested in doing is

assertThat(repository.getConcreteNumberTrivia(number)).isEqualTo(Success(entity))

I feel like there should be a shortcut for where we don't need to create these runBlocking scopes or to create result variables to hold the result.

And the only thing i am interested in doing is

assertThat(repository.getConcreteNumberTrivia(number)).isEqualTo(Success(entity))

From Truth's perspective, this is functionality equivalent to

assertThat(Success(entity)).isEqualTo(Sucess(entity))

The library is not invoking your suspend function and thus has no control over it. Your test body invokes the suspend function and, thus, your test body needs runBlocking.

What you're asking for is a framework that supports writing

@Test suspend fun myTest() {
    val result = repository.getConcreteNumberTrivia(number)
    coVerify { mockRemoteDataSource.getConcreteNumberTrivia(number) }
    assertThat(result).isEqualTo(Success(entity))
}

which has nothing to do with Truth and is what I linked earlier.

True, makes sense. Is there any such XUnit framework that supports this? I see that a issue is opened for JUnit 5 to support this junit-team/junit5#1914

PS: Big fan jake ✌️

I do not know of any. But I'll start following that JUnit 5 issue (despite being extremely bearish on 5.x).

If you wanted to get really, really creative with JUnit 4 I believe you can do this as a custom test runner. You would discover the test methods yourself which would be in the form

@Test public Object testName(Continuation<? extends Unit> continuation)

and then invoke them with some very low-level coroutine machinery.

I could be convinced to be nerd-sniped by this task... I just have to find the time...

And, of course, the big problem here is that JUnit 4 test runners do not compose so you couldn't combine it with parameterized or anything else.

Sounds good will try to implement this.