Skip to content

Support test methods with Kotlin suspend modifier #1914

@IRus

Description

@IRus

Goals

Support running suspend test in JUnit Jupiter:

class Kit {
    @Test 
    suspend fun foo() {
        delay(1000) // suspend call
        assertEquals(1, 1)
    } 
}

Currently, such test can be written this way:

class Kit {
    @Test 
    fun foo() = runBlocking {
        delay(1000) // suspend call
        assertEquals(1, 1)
        assertThrows { /* ... */ } 
        Unit // test should return void, but `assertThrows` returns `Throwable`, so `foo` returns `Throwable` too 
    } 
}

Also, will be nice to provide CoroutineScope through params, or as receiver in extension:

class Kit {
    suspend fun foo(scope: CoroutinesScope) {  /* ... */  } // (1)
    suspend fun CoroutinesScope.foo() {  /* ... */  } // (2)
}

1 and 2 actually the same on bytecode level. suspend is optional.

And finally, support for runBlockingTest:

class Kit {
    suspend fun foo(scope: TestCoroutinesScope) {  /* ... */  }
    suspend fun TestCoroutinesScope.foo() {  /* ... */  } 
}

What can be done currently

ParameterResolver can be used to provide stubs for Continuation, CoroutineScope and TestCoroutineScope. These stub arguments can be replaced with real arguments in invocation.

Problems

Current extensions points not enough to implement this feature as extensions, since:

  1. Discovery. Jupiter discovers tests that returns void, but suspend fun returns Object;
  2. Invocation. InvocationInterceptor in 5.5-M1(SNAPSHOT) don't providing mechanism to override actual invocation, only to decoration of existing invocation. Conversion of method to kotlinFunction, and then executing using callSuspend is necessary to execute suspend fun.

Also, my slides about this topic.

Metadata

Metadata

Assignees

Projects

Status

In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions