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

如何对使用goAsync()的Android BroadcastReceiver进行单元测试

问题根因

goAsync() 方法只有在Android系统触发onReceive回调时才会返回有效的PendingResult实例,手动调用onReceive时没有系统注入的PendingResult上下文,所以默认返回null,导致空指针异常。

解决方案

可以通过Mock依赖、改造可测试性的方式完成单元测试,推荐使用Mockito作为Mock框架,具体实现如下:

方式1:优化原有代码可测试性后编写用例

先对原有Receiver做最小改造,把异步执行器提到成员变量,方便测试注入同步执行器,避免异步等待:

public class NotificationReceiver extends BroadcastReceiver {
    // 执行器改为成员变量,方便测试注入
    private ExecutorService executor = Executors.newSingleThreadExecutor();

    @VisibleForTesting
    void setExecutor(ExecutorService executor) {
        this.executor = executor;
    }

    public void onReceive(final Context context, final Intent intent) {
       final PendingResult asyncResult = goAsync();
       asycTask(new Runnable() {
            @Override
            public void run() {
                handleAction(context, intent);  // 耗时操作
                asyncResult.finish();
            }
        });   
    }

    private void asycTask(final Runnable task) {
        try {
            executor.execute(task);
        } catch (Throwable ex) {}
    }

    // handleAction等其他逻辑省略
}

对应的测试代码:

import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import android.content.BroadcastReceiver.PendingResult;

@RunWith(MockitoJUnitRunner.class)
public class NotificationReceiverTest {
    @Mock
    private Context application;
    @Mock
    private Intent intent;
    @Mock
    private PendingResult pendingResult;

    @Test
    public void testOnReceive() {
        NotificationReceiver receiver = new NotificationReceiver();
        // 注入Mock的PendingResult,解决goAsync返回null的问题
        receiver.setPendingResult(pendingResult);
        // 注入同步执行器,让异步任务直接在当前测试线程运行,无需等待
        ExecutorService syncExecutor = new ExecutorService() {
            @Override
            public void execute(Runnable command) {
                command.run();
            }
            // 其余未用到的接口方法可默认空实现
        };
        receiver.setExecutor(syncExecutor);

        // 调用待测试方法
        receiver.onReceive(application, intent);

        // 直接验证逻辑,不需要额外等待
        // 这里可以加handleAction相关的逻辑校验
        // 验证finish方法被正确调用
        verify(pendingResult, times(1)).finish();
    }
}

方式2:不改原有代码的测试方案

如果不想修改原有Receiver代码,可以通过Mockito的spy能力捕获异步任务,主动执行:

@Test
public void testOnReceiveWithoutModifySource() {
    NotificationReceiver receiver = spy(new NotificationReceiver());
    receiver.setPendingResult(pendingResult);
    // 捕获传入的异步任务
    AtomicReference<Runnable> taskCaptor = new AtomicReference<>();
    doAnswer(invocation -> {
        taskCaptor.set(invocation.getArgument(1));
        return null;
    }).when(receiver).asycTask(any(ExecutorService.class), any(Runnable.class));

    // 调用待测试方法
    receiver.onReceive(application, intent);

    // 主动执行捕获到的异步任务
    taskCaptor.get().run();

    // 验证逻辑
    verify(pendingResult, times(1)).finish();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 02:09:01