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

Android中如何通过Unit Test或Instrumented Test测试Alarm Manager

Alarm Manager 闹钟设置校验测试方案

一、单元测试(本地JVM测试,无需真机/模拟器)

单元测试核心思路是Mock系统AlarmManager、Context、PendingIntent等依赖,验证调用参数是否符合预期,这里用MockK作为Mock框架举例:

  • 依赖配置(build.gradle.kts)
testImplementation "io.mockk:mockk:1.13.8"
testImplementation "junit:junit:4.13.2"
  • 测试代码示例
class AlarmSetterTest {
    private val mockContext = mockk<Context>()
    private val mockAlarmManager = mockk<AlarmManager>()
    private val mockPendingIntent = mockk<PendingIntent>()

    @Before
    fun setUp() {
        every { mockContext.getSystemService(Context.ALARM_SERVICE) } returns mockAlarmManager
        every { PendingIntent.getBroadcast(any(), eq(1), any<Intent>(), eq(0)) } returns mockPendingIntent
        // 固定当前时间,避免测试受时间影响
        mockkStatic(LocalDateTime::class)
        val fixedNow = LocalDateTime.of(2024, 5, 20, 10, 0, 0)
        every { LocalDateTime.now() } returns fixedNow
    }

    @Test
    fun `alarm should be set to next day 1:02 AM`() {
        // 执行给定的闹钟设置逻辑
        val alarmManager1 = mockContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val alarmIntent1 = Intent(mockContext, AlarmReceiver::class.java)
        val requestCode1 = 1
        val pendingIntent1 = PendingIntent.getBroadcast(mockContext, requestCode1, alarmIntent1, 0)
        val calendar: Calendar = Calendar.getInstance()
        val currentDateTime = LocalDateTime.now()
        calendar.set(
            currentDateTime.year,
            currentDateTime.monthValue - 1,
            currentDateTime.dayOfMonth + 1,
            1,
            2,
            0
        )
        alarmManager1.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent1)

        // 验证参数是否正确
        val expectedCalendar = Calendar.getInstance().apply {
            set(2024, 4, 21, 1, 2, 0)
        }
        verify(exactly = 1) {
            mockAlarmManager.setExactAndAllowWhileIdle(
                eq(AlarmManager.RTC_WAKEUP),
                eq(expectedCalendar.timeInMillis),
                eq(mockPendingIntent)
            )
        }
    }

    @After
    fun tearDown() {
        unmockkAll()
    }
}

注意:单元测试只能验证你的代码调用逻辑是否正确,无法验证系统层面闹钟是否真的触发,真实触发校验需要用插桩测试

二、插桩测试(需运行在真机/模拟器)

插桩测试可以直接调用系统服务,验证闹钟是否真的被注册到系统中:

  • 依赖配置(build.gradle.kts)
androidTestImplementation "androidx.test.ext:junit:1.1.5"
androidTestImplementation "androidx.test:core:1.5.0"
  • 测试代码示例
@RunWith(AndroidJUnit4::class)
class AlarmManagerInstrumentedTest {
    @Test
    fun verifyAlarmIsRegistered() {
        val context = ApplicationProvider.getApplicationContext<Context>()
        // 先执行给定的闹钟设置代码
        val alarmManager1 = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val alarmIntent1 = Intent(context, AlarmReceiver::class.java)
        val requestCode1 = 1
        // 用FLAG_NO_CREATE判断对应PendingIntent是否已经被注册
        val pendingIntent1 = PendingIntent.getBroadcast(context, requestCode1, alarmIntent1, PendingIntent.FLAG_NO_CREATE or PendingIntent.FLAG_IMMUTABLE)
        // PendingIntent不为空即可证明闹钟已经注册到系统
        assertNotNull(pendingIntent1)

        // Android 12及以上可以通过getNextAlarmClock()验证下一个闹钟的时间是否符合预期
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            val nextAlarm = alarmManager1.nextAlarmClock
            assertNotNull(nextAlarm)
        }
    }
}

额外修复建议:你提供的代码里PendingIntent的flag用了0,Android 12及以上要求必须指定PendingIntent.FLAG_IMMUTABLE或者PendingIntent.FLAG_MUTABLE,否则会抛出异常,建议把flag改成PendingIntent.FLAG_IMMUTABLE适配高版本系统。

内容的提问来源于stack exchange,提问作者Muhammad Zaryab Rafique

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 22:27:03