You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IntelliJ运行Android单元测试时提示‘Test events were not received’求助

Android单元测试报错"Test events were not received"排查与修复

我正在学习Android单元测试,用IntelliJ运行测试时失败,提示"Test events were not received",堆栈跟踪无多余细节。试过增删依赖、参考相关方案都没解决,目前跟着Udemy的TDD课程学习。

测试类代码

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import petros.efthymiou.groovy.utils.BaseUnitTest
import petros.efthymiou.groovy.utils.getValueForTest


class PlayListViewModelShould:BaseUnitTest() {


    private val repository: PlayListRepository = mock()
    private val playList = mock<List<PlayList>>()
    private val expected = Result.success(playList)
    private val exception = java.lang.RuntimeException("SOMETHING NOT RIGHT")


    @OptIn(ExperimentalCoroutinesApi::class)
    @Test
    suspend fun getPlaylistsFromRepository()= runTest{
        val viewModel = mockSuccesfulCase()

        viewModel.playlists.getValueForTest()

        verify(repository,times(1)).getPlaylists()
    }
    @OptIn(ExperimentalCoroutinesApi::class)
    @Test
    fun emitPlaylistsFromRepository()= runTest {

        val viewModel = mockSuccesfulCase()
        assertEquals(expected, viewModel.playlists.getValueForTest())

    }
    @OptIn(ExperimentalCoroutinesApi::class)
    @Test
    fun emitErrorWhenRecieveError() {
        runTest {
            whenever(repository.getPlaylists()).thenReturn(
                flow {
                    emit(Result.failure<List<PlayList>>(exception))
                }
            )
        }
        val viewModel = PlayListViewModel(repository)
        assertEquals(java.lang.RuntimeException("another error"), viewModel.playlists.getValueForTest()!!.exceptionOrNull())
    }


    private fun mockSuccesfulCase(): PlayListViewModel {
        runBlocking {
            whenever(repository.getPlaylists()).thenReturn(
                flow {
                    emit(expected)
                }
            )
        }

        return PlayListViewModel(repository)
    }

}

Gradle配置

android {
    compileSdkVersion 30

    defaultConfig {
        applicationId "petros.efthymiou.groovy"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    testOptions {
        execution 'ANDROIDX_TEST_ORCHESTRATOR'

        unitTests.all {
            useJUnitPlatform()
        }
    }



    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
        freeCompilerArgs = freeCompilerArgs + "-Xallow-result-return-type"
    }

    testOptions {
        animationsDisabled = true
    }
    buildFeatures {
        viewBinding true
    }
}

dependencies {

    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.0-alpha04'
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
    implementation 'com.jakewharton.espresso:okhttp3-idling-resource:1.0.0'


//    testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0'
    testImplementation 'org.mockito:mockito-inline:2.21.0'
    testImplementation 'androidx.arch.core:core-testing:2.1.0'
    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8'
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.1")
    testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0'
    testImplementation "org.mockito:mockito-core:4.3.1"
    androidTestImplementation "org.mockito:mockito-android:3.10.0"
    testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1'
    testImplementation 'org.junit.vintage:junit-vintage-engine:5.9.1'


    androidTestImplementation 'com.jakewharton.espresso:okhttp3-idling-resource:1.0.0'
    androidTestImplementation 'androidx.test:runner:1.5.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
    androidTestImplementation "org.mockito:mockito-core:4.3.1"

    androidTestImplementation 'junit:junit:4.13.2'
    androidTestImplementation "org.robolectric:robolectric:4.3.1"
    androidTestImplementation('com.schibsted.spain:barista:3.6.0') {
        exclude group: 'org.jetbrains.kotlin' // Only if you already use Kotlin in your project
    }
}

问题根源与修复步骤

1. 依赖版本混乱是核心问题

  • 协程库版本不匹配:coroutines-core用1.3.9,coroutines-android用1.6.4,coroutines-test用1.3.8,版本差异会导致测试协程环境初始化失败
  • Mockito版本冲突:mockito-inline是2.21.0,mockito-core是4.3.1,mockito-kotlin是4.0.0,跨大版本的依赖会引发兼容性问题
  • JUnit混合使用:同时引入JUnit 5(Jupiter)和JUnit 4兼容引擎(Vintage),导致测试运行器冲突

修复依赖配置:

// 在android块上方定义统一版本变量
ext {
    coroutines_version = "1.6.4"
    junit_jupiter_version = "5.9.1"
    mockito_version = "4.8.1"
}

dependencies {
    // 保留原有implementation依赖...

    // 清理测试依赖,统一版本
    testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
    testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version"
    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_jupiter_version"
    testImplementation "org.mockito:mockito-core:$mockito_version"
    testImplementation "org.mockito:mockito-inline:$mockito_version"
    testImplementation "org.mockito.kotlin:mockito-kotlin:4.1.0"
    testImplementation 'androidx.arch.core:core-testing:2.2.0'

    // 清理androidTest依赖版本
    androidTestImplementation "org.mockito:mockito-android:$mockito_version"
    // 保留其他androidTest依赖...
}

2. 测试代码逻辑错误

  • emitErrorWhenRecieveError中,mock配置在runTest块内,但ViewModel初始化在块外,导致mock逻辑未生效;且断言的异常信息与mock的不一致
  • mockSuccesfulCase使用runBlocking而非测试专用的runTest,可能导致线程阻塞,测试事件无法传递

修复测试代码:

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import petros.efthymiou.groovy.utils.BaseUnitTest
import petros.efthymiou.groovy.utils.getValueForTest

class PlayListViewModelShould: BaseUnitTest() {

    private val repository: PlayListRepository = mock()
    private val playList = mock<List<PlayList>>()
    private val expected = Result.success(playList)
    private val exception = RuntimeException("SOMETHING NOT RIGHT")

    @OptIn(ExperimentalCoroutinesApi::class)
    @Test
    fun getPlaylistsFromRepository() = runTest {
        val viewModel = mockSuccesfulCase()
        viewModel.playlists.getValueForTest()
        verify(repository, times(1)).getPlaylists()
    }

    @OptIn(ExperimentalCoroutinesApi::class)
    @Test
    fun emitPlaylistsFromRepository() = runTest {
        val viewModel = mockSuccesfulCase()
        assertEquals(expected, viewModel.playlists.getValueForTest())
    }

    @OptIn(ExperimentalCoroutinesApi::class)
    @Test
    fun emitErrorWhenRecieveError() = runTest {
        // 将mock配置与ViewModel初始化放在同一个runTest块内
        whenever(repository.getPlaylists()).thenReturn(
            flow {
                emit(Result.failure<List<PlayList>>(exception))
            }
        )

        val viewModel = PlayListViewModel(repository)
        // 断言正确的异常对象
        assertEquals(exception, viewModel.playlists.getValueForTest()!!.exceptionOrNull())
    }

    private fun mockSuccesfulCase(): PlayListViewModel = runTest {
        whenever(repository.getPlaylists()).thenReturn(
            flow {
                emit(expected)
            }
        )
        PlayListViewModel(repository)
    }
}

3. 检查IntelliJ测试配置

打开Run > Edit Configurations,确认每个测试类的运行器选择JUnit 5 (Jupiter),而非JUnit 4。


内容的提问来源于stack exchange,提问作者Mohamed Rimshad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 04:05:19