使用Mockito测试Android应用:doThrow方法致测试挂起无结果求助
嘿,我碰到过类似的AsyncTask测试坑!你现在遇到的挂起问题,大概率是因为AsyncTask的内部线程机制,加上Mockito spy真实实例时的兼容性问题导致的。咱们一步步来拆解和修复:
1. 别再Spy真实的AsyncTask实例了!
AsyncTask内部维护着自己的线程池和任务状态,直接spy真实的PackageDownloader实例很容易让Mockito的拦截逻辑和AsyncTask的内部运作冲突,导致线程卡住。换个思路,直接mock整个PackageDownloader类:
// 直接mock类,不用搞真实实例的spy PackageDownloader mockPackageDownloader = Mockito.mock(PackageDownloader.class); HttpURLConnection connectionMock = Mockito.mock(HttpURLConnection.class); // 正常模拟createConnection方法 Mockito.doReturn(connectionMock) .when(mockPackageDownloader) .createConnection(Mockito.any(URL.class)); // 现在再模拟get()抛异常就不会挂起了 Mockito.doThrow(new InterruptedException()) .when(mockPackageDownloader) .get();
2. 检查你的get()方法能不能被Mockito拦截
如果你的PackageDownloader重写了AsyncTask的get()方法,千万别把它写成final的!Mockito默认没法拦截final方法,这会导致你的doThrow完全不生效,进而出现莫名其妙的挂起。如果实在要用final方法,得开启Mockito的inline mock支持,但真心不推荐——尽量让测试方法保持非final。
3. 确认downloadPackage()用的是你mock的实例
这是很多人容易犯的低级错误:你辛辛苦苦mock了实例,结果downloadPackage()内部又new了一个全新的PackageDownloader,那你的mock完全白搭!一定要确保downloadPackage()使用的是你创建的mockPackageDownloader对象,比如通过依赖注入传进去。
4. 妥善处理InterruptedException
InterruptedException是受检异常,测试时要么在测试方法上声明抛出它,要么在内部捕获处理,不然线程可能因为未处理的异常卡住:
@Test(expected = InterruptedException.class) public void testDownloadPackageThrowsInterruptedException() throws InterruptedException { // 先做好mock设置 // 然后调用downloadPackage()或者直接触发get() downloadPackage(); }
额外小建议:换掉AsyncTask吧
AsyncTask早就被Android官方废弃了,它的线程模型在测试时真的麻烦不断。如果项目允许,建议改用Coroutines或者RxJava来实现异步任务,这些框架的测试支持友好得多,Mockito模拟异常也会顺畅很多。
内容的提问来源于stack exchange,提问作者annaoomph

