单元测试:如何验证AsyncTask启动并避免其实际执行?
当然可以搞定!结合Robolectric 3.0和Mockito,完全能做到验证AsyncTask被成功启动,同时避免它执行那些会抛异常的逻辑。下面给你两种实用的方案,按需选择就行:
方案一:Mock AsyncTask 实例
这种方式适合愿意稍微调整被测类代码、追求更彻底隔离的场景——我们直接给被测类注入一个Mock的AsyncTask,这样它启动的就是假任务,自然不会触发真实的异常逻辑。
步骤拆解:
- 先把被测类里创建AsyncTask的逻辑抽出来,让它支持依赖注入(比如通过构造方法传入AsyncTask实例),这样测试时就能替换成Mock对象。
- 用Mockito创建AsyncTask的Mock实例,注入到被测类中。
- 执行被测方法后,验证Mock的
execute()方法被调用过就行。
代码示例:
// 被测类(稍微重构后支持依赖注入) public class MyTargetClass { private final MyAsyncTask task; // 构造注入,方便测试时替换成Mock public MyTargetClass(MyAsyncTask task) { this.task = task; } public void doSomeWork() { task.execute(); } public static class MyAsyncTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... voids) { // 会抛出异常的逻辑 throw new RuntimeException("Oops!"); } } } // 测试类 @RunWith(RobolectricGradleTestRunner.class) public class MyTargetClassTest { @Test public void testAsyncTaskIsStarted() { // 创建Mock的AsyncTask MyTargetClass.MyAsyncTask mockTask = Mockito.mock(MyTargetClass.MyAsyncTask.class); // 注入Mock实例到被测类 MyTargetClass target = new MyTargetClass(mockTask); // 执行被测方法 target.doSomeWork(); // 验证AsyncTask的execute方法确实被调用了 Mockito.verify(mockTask).execute(); } }
如果不想重构代码,也可以用PowerMock来Mock内部类的创建逻辑,但优先推荐重构让代码更具可测试性哦。
方案二:借助Robolectric的ShadowAsyncTask 拦截执行
如果不想改动被测类代码,Robolectric自带的ShadowAsyncTask可以帮我们拦截AsyncTask的执行,阻止它跑后台逻辑。
步骤拆解:
- 执行被测方法后,通过Robolectric的Shadow工具获取已经启动的AsyncTask。
- 要么直接取消任务,要么提前配置Robolectric暂停后台任务调度,不让后台逻辑执行。
代码示例(暂停后台调度版):
@RunWith(RobolectricGradleTestRunner.class) public class MyTargetClassTest { @Before public void setup() { // 提前让Robolectric暂停后台任务调度,AsyncTask只会被启动但不执行 Robolectric.getBackgroundScheduler().pause(); } @Test public void testAsyncTaskIsStartedWithoutExecution() { MyTargetClass target = new MyTargetClass(); // 执行被测方法,AsyncTask会被启动但不会跑后台逻辑 target.doSomeWork(); // 验证后台调度器里确实有一个待执行的AsyncTask assertThat(Robolectric.getBackgroundScheduler().size()).isEqualTo(1); } }
也可以选择在启动任务后直接拦截:
@Test public void testAsyncTaskIsStarted() { MyTargetClass target = new MyTargetClass(); target.doSomeWork(); // 获取所有已启动的AsyncTask List<AsyncTask> tasks = ShadowApplication.getInstance().getStartedTasks(); // 验证任务数量符合预期 assertThat(tasks.size()).isEqualTo(1); // 取消任务,阻止它执行后台逻辑 tasks.get(0).cancel(true); }
两种方案各有优劣:Mock方式隔离性更强,适合长期维护的代码;Shadow类方式不需要改动业务代码,适合快速验证场景。
内容的提问来源于stack exchange,提问作者d3xter
相关产品推荐
相关产品推荐

