Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin multiplatform: kotlinx.coroutines.test library not visible in commonTest module

I have difficulties integrating kotlin testing framework for coroutines kotlinx.coroutines.test with multiplatform project that targets Android (and ios in the future)

My common code relies heavily on coroutines but I'm unable to test them (it looks like the testing library is not in the classpath)

build.gradle for common module:

plugins {
    id 'org.jetbrains.kotlin.multiplatform'
    id 'com.android.library'
    id 'kotlin-kapt'
}

android {
    defaultConfig {
        compileSdkVersion 28
        javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true
    }
    lintOptions {
        checkAllWarnings true
    }
}

def coroutinesVersion = "1.3.0-M2"
def mockKVersion = "1.9.3"

kotlin {
    targets {
        fromPreset(presets.android, 'android')
    }

    sourceSets {
        commonMain.dependencies {
            //Kotlin
            implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version"
            implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" //used in Log implementation
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutinesVersion"
        }
        commonTest.dependencies {
            //Kotlin
            implementation "org.jetbrains.kotlin:kotlin-test-common:$kotlin_version"
            implementation "org.jetbrains.kotlin:kotlin-test-annotations-common:$kotlin_version"
            //Coroutines testing
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutinesVersion"
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"
            implementation "io.mockk:mockk-common:$mockKVersion"
        }
        androidMain.dependencies {
            implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
        }
        androidTest.dependencies {
            implementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
            implementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
            implementation "io.mockk:mockk:$mockKVersion"
        }
    }
}

/*
* Due to the current limitations, it requires that the Android target is created before the kapt dependencies are configured,
* which needs to be done in a top-level dependencies { ... } block rather than within Kotlin source sets dependencies.
*/
dependencies {
    implementation 'javax.annotation:javax.annotation-api:1.3.2'
    kapt 'com.google.auto.factory:auto-factory:1.0-beta6@jar'
    compileOnly "com.google.auto.factory:auto-factory:1.0-beta6"
}

Example test in commonTest source set:

package some.package.common.test

import kotlin.test.Test
import kotlin.test.assertTrue

class SomeTest {

    @Test
    fun `should pass`() {
        //none of the kotlinx.coroutines.test content is available here (eg. runBlockingTest)
        assertTrue { 2 + 2 == 4 }
    }
}
like image 436
Marcin Avatar asked Jun 28 '19 09:06

Marcin


1 Answers

It turns out that kotlinx.coroutines.test is a JVM library, so it can’t be used in common module.

Possible solutions:

  • Write tests and use the library in Android (or other JVM compatible) module
  • Define your own common function that will use JVM/Native implementation of runBlocking (see https://youtrack.jetbrains.com/issue/KT-22228)

//TestUtil.kt in commonTest source set
expect fun runBlocking(block: suspend () -> Unit)

//TestUtil.kt in androidTest source set
actual fun runBlocking(block: suspend () -> Unit) = kotlinx.coroutines.runBlocking { block() }

//example usage in commonTest source set
class Test {
    @Test
    fun shouldPass() = runBlocking {
        assertTrue { 2 + 2 == 4 }
    }
}
like image 129
Marcin Avatar answered Nov 24 '22 00:11

Marcin