无法在单元测试中模拟服务

Unable to mock service in Unit test

美好的一天!我有一项服务可以观察在创建方法中从数据源收到的流量。

我正在尝试创建单元测试以验证服务是否会存储收到的值。但是,当我尝试开始测试时,它会抛出方法 postAtFrontOfQueue in android.os.Handler not mocked.

完整的例外消息:java.lang.RuntimeException: Method postAtFrontOfQueue in android.os.Handler not mocked. See http://g.co/androidstudio/not-mocked for details.

你能帮我弄清楚我做错了什么吗?

这是我的服务:

override fun onCreate() {
        super.onCreate()

        val onPressIntent = Intent(this, MainActivity::class.java)
        val pendingIntent =
            PendingIntent.getActivity(this, 1, onPressIntent, PendingIntent.FLAG_IMMUTABLE)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            val name = getString(R.string.sensor_notification_channel_name)
            val importance = IMPORTANCE_DEFAULT
            val channel = NotificationChannel(SENSOR_CHANNEL_ID, name, importance)
            val manager: NotificationManager =
                getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

            manager.createNotificationChannel(channel)
        }

        val notification = NotificationCompat.Builder(this, SENSOR_CHANNEL_ID)
            .setContentTitle(this.getString(R.string.sensor_notification_tittle))
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentText(getString(R.string.sensor_notification_description))
            .setContentIntent(pendingIntent)
        startForeground(1, notification.build())

        lifecycleScope.launchWhenCreated {
            gravityFluctuationUseCase.deletePreviousValue()
        }

        gravityFluctuationUseCase.getFluctuationsRecord().asLiveData().observe(this){ value ->
            Log.d("TAG", "Sensor event: $value")
            lifecycleScope.launch(dispatcher){
                gravityFluctuationUseCase.addNewItem(value)
            }
        }
    }

测试class:

@ExtendWith(InstantExecutorExtension::class)
class SensorServiceTest : KoinTest {

    private lateinit var useCase: GravityFluctuationUseCase
    private lateinit var service: SensorService
    private val dispatcher = TestCoroutineDispatcher()

    @BeforeEach
    fun setUp() {
        val context: Context = mockk(relaxed = true) {
            every { applicationContext } returns this
        }
        useCase = mockk(relaxed = true)

        startKoin {
            modules(
                module {
                    single { useCase }
                    single { Dispatchers.Default }
                }
            )
        }
        val notificationService: android.app.NotificationManager = mockk(relaxed = true)
        val lifecycle = LifecycleRegistry(mockk(relaxed = true))
        lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START)
        service = spyk(SensorService()){
            every { applicationContext } returns context
            every { this@spyk.lifecycle } returns lifecycle
            every { getSystemService(Context.NOTIFICATION_SERVICE) } returns notificationService
            every { packageManager } returns mockk(relaxed = true)
        }

        mockkStatic(PendingIntent::class)
        every { PendingIntent.getActivity(any(), any(), any(), any()) } returns mockk(relaxed = true)

        mockkConstructor(NotificationCompat.Builder::class)
        every { anyConstructed<NotificationCompat.Builder>().build() } returns mockk(relaxed = true)

        Dispatchers.setMain(dispatcher)
    }

    @AfterEach
    fun tearDown() {
        stopKoin()
        unmockkConstructor(NotificationCompat.Builder::class)
        unmockkStatic(PendingIntent::class)
        Dispatchers.resetMain()
    }

    @Test
    fun verify_service_adding_new_value_when_receive() {
        val initVal = 1f
        val initFlow = flowOf(initVal)
        val resultList = mutableListOf<Float>()
        coEvery { useCase.getFluctuationsRecord() } returns initFlow
        coEvery { useCase.addNewItem(initVal) }.answers {
            resultList.add(initVal)
        }

        service.onCreate()
        Truth.assertThat(resultList)
            .contains(initVal)
    }
}

如@Demigod 所示,将行 unitTests.returnDefaultValues = true 添加到您的模块 build.gradle:

    testOptions {
        unitTests.returnDefaultValues = true // add this
        unitTests.all {
            useJUnitPlatform()
        }