jUnit4 - Почему при тестировании приостанавливаемой функции возникает ошибка RuntimeException: ... AndroidJUnit4 не может быть загружен?

Когда я тестирую простой БД, написанный с Room, тест, ожидающий исключения, завершается ошибкой, если функции dao объявлены с suspend. Ошибка:

java.lang.RuntimeException: Delegate runner 'androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner' for AndroidJUnit4 could not be loaded.

Моя сущность:

@Entity(indices = [Index(value = ["user_name"], unique = true)])
class User (
    @ColumnInfo(name = "user_name") var name: String,
    @PrimaryKey(autoGenerate = true) var id: Long = 0
)

Как видите, я хочу, чтобы база данных не сохраняла User с таким же user_name содержание.

Мой класс дао:

@Dao
interface UserDao {
    @Insert
    fun insertUser(user: User): Long

    @Delete
    fun deleteUser(user: User)
}

И мой тест:

@Test fun insertUser() {
    val jojo = User("Jojo")
    val id = userDao.insertUser(jojo)

    Assert.assertNotEquals(null, id)
}

// Inserting the same `User` must raise a `SQLiteConstraintException`
@Test(expected = SQLiteConstraintException::class)
fun insertSameUser() {
    val jojo = User("Jojo")

    userDao.insertUser(jojo)
    userDao.insertUser(jojo)
}

На этом этапе все тесты проходят, как и ожидалось.

Проблема возникает, когда я меняю свой класс dao на использование suspend функции:

@Dao
interface UserDao {
    @Insert
    suspend fun insertUser(user: User): Long

    @Delete
    suspend fun deleteUser(user: User)
}

Я меняю свои тесты следующим образом:

@Test fun insertUser()= runBlocking {
    val jojo = User("Jojo")
    val id = userDao.insertUser(jojo)

    Assert.assertNotEquals(null, id)
}

// Inserting the same `User` must raise a `SQLiteConstraintException`
@Test(expected = SQLiteConstraintException::class)
fun insertSameUser() = runBlocking {
    val jojo = User("Jojo")

    userDao.insertUser(jojo)
    userDao.insertUser(jojo)
}

Теперь проверка приостанавливаемых функций не удалась!

А RuntimeException Поднялся:

java.lang.RuntimeException: Delegate runner 'androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner' for AndroidJUnit4 could not be loaded.
at androidx.test.ext.junit.runners.AndroidJUnit4.throwInitializationError(AndroidJUnit4.java:92)
at androidx.test.ext.junit.runners.AndroidJUnit4.loadRunner(AndroidJUnit4.java:82)
at androidx.test.ext.junit.runners.AndroidJUnit4.loadRunner(AndroidJUnit4.java:51)
at androidx.test.ext.junit.runners.AndroidJUnit4.<init>(AndroidJUnit4.java:46)
at java.lang.reflect.Constructor.newInstance(Native Method)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
at androidx.test.internal.runner.junit4.AndroidAnnotatedBuilder.runnerForClass(AndroidAnnotatedBuilder.java:63)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at androidx.test.internal.runner.AndroidRunnerBuilder.runnerForClass(AndroidRunnerBuilder.java:153)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at androidx.test.internal.runner.TestLoader.doCreateRunner(TestLoader.java:73)
at androidx.test.internal.runner.TestLoader.getRunnersFor(TestLoader.java:104)
at androidx.test.internal.runner.TestRequestBuilder.build(TestRequestBuilder.java:789)
at androidx.test.runner.AndroidJUnitRunner.buildRequest(AndroidJUnitRunner.java:543)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:386)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1959)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance(Native Method)
at androidx.test.ext.junit.runners.AndroidJUnit4.loadRunner(AndroidJUnit4.java:72)
... 16 more
Caused by: org.junit.runners.model.InitializationError
at org.junit.runners.ParentRunner.validate(ParentRunner.java:418)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:84)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:65)
at androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner.<init>(AndroidJUnit4ClassRunner.java:43)
at androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner.<init>(AndroidJUnit4ClassRunner.java:48)
... 18 more

Я обнаружил, что ошибка возникает из-за теста insertSameUser, и если я изменю insertSameUser как следует, ошибок больше нет:

@Test(expected = SQLiteConstraintException::class)
fun insertSameUser() = runBlocking {
    val jojo = User("Jojo")
    userDao.insertUser(jojo)
    userDao.insertUser(jojo)

    Assert.assertEquals(null, "fake")
}

Если я удалю @RunWith(AndroidJUnit4::class)как предлагается здесь, тогда тест не проходит сjava.lang.Exception: Method insertSameUser() should be void. Здесь снова, если я добавлю фиктивный тест, как указано выше, тогда тест будет работать.

Есть у кого-нибудь идеи?

Зависимости:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.core:core-ktx:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'

    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'

    //Room
    def room_version = "2.2.1"
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor
    // optional - Kotlin Extensions and Coroutines support for Room
    implementation "androidx.room:room-ktx:$room_version"
    // Test helpers
    testImplementation "androidx.room:room-testing:$room_version"
}

0 ответов

Другие вопросы по тегам