如何让单元测试等待Retrofit响应?Android Robolectric测试问题
解决Retrofit异步响应的测试等待问题
你的测试提前结束是因为JUnit测试方法在主线程执行完毕后就会终止,不会等待Retrofit的异步回调完成。这里有几个实用的解决办法,帮你让测试等待异步操作结束:
方法一:使用CountDownLatch阻塞测试线程
这是最直接的方式,通过CountDownLatch让测试线程等待到异步回调执行完毕:
@Test public void testCalculateRoute() throws InterruptedException { System.out.println("Start Test"); MutableLiveData<ApiResponseWithDataList<LoginData>> loginData = new MutableLiveData<>(); MutableLiveData<ApiResponseWithData<ItineraryResponseData>> itineraryData = new MutableLiveData<>(); // 创建CountDownLatch,计数为1(等待1次回调完成) CountDownLatch latch = new CountDownLatch(1); profileRepository.login(loginData, EMAIL, PASS); createActivitiesWithIntents(); loginData.observe(loginActivity, (@Nullable ApiResponseWithDataList<LoginData> loginResponse) -> { System.out.println("Do login for get Access Token"); String accessToken = loginResponse.getData().getAccessToken(); ItineraryBody itineraryBody = new ItineraryBody(); mapRepository.calculateRoute(itineraryData, accessToken, itineraryBody); }); itineraryData.observe(mapActivity, (@Nullable ApiResponseWithData<ItineraryResponseData> itineraryResponse) -> { System.out.println("Getting route"); System.out.println("Finish Test"); // 回调执行完成,计数减1 latch.countDown(); }); // 强制刷新Robolectric主线程任务,确保LiveData回调被触发 Robolectric.flushForegroundThreadScheduler(); // 等待回调完成,设置10秒超时避免无限等待 latch.await(10, TimeUnit.SECONDS); }
方法二:Mock Repository(更推荐的单元测试方式)
单元测试的核心是验证业务逻辑,而非真实网络请求。你可以用Mockito来Mock你的LoginRepository和MapRepository,直接返回预设的测试数据,既不用等待网络请求,测试也更稳定:
@RunWith(RobolectricTestRunner.class) public class RouteTest { // 使用@Mock创建Mock对象 @Mock LoginRepository profileRepository; @Mock MapRepository mapRepository; private ActivityController<LoginActivity> loginController; private ActivityController<MapActivity> mapController; private LoginActivity loginActivity; private MapActivity mapActivity; private void createActivitiesWithIntents() { loginActivity = loginController.create().start().get(); mapActivity = mapController.create().start().get(); } @Before public void setUp() { MockitoAnnotations.openMocks(this); // 初始化Mock对象 loginController = Robolectric.buildActivity(LoginActivity.class); mapController = Robolectric.buildActivity(MapActivity.class); } @Test public void testCalculateRoute() { System.out.println("Start Test"); // 预设登录返回的数据 ApiResponseWithDataList<LoginData> mockLoginResponse = new ApiResponseWithDataList<>(); mockLoginResponse.getData().setAccessToken("test-token"); MutableLiveData<ApiResponseWithDataList<LoginData>> loginData = new MutableLiveData<>(mockLoginResponse); // 预设路线计算返回的数据 ApiResponseWithData<ItineraryResponseData> mockItineraryResponse = new ApiResponseWithData<>(); MutableLiveData<ApiResponseWithData<ItineraryResponseData>> itineraryData = new MutableLiveData<>(mockItineraryResponse); // 配置Mock方法的返回值 when(profileRepository.login(any(), eq(EMAIL), eq(PASS))).thenReturn(loginData); when(mapRepository.calculateRoute(any(), eq("test-token"), any())).thenReturn(itineraryData); createActivitiesWithIntents(); // 触发登录逻辑 profileRepository.login(loginData, EMAIL, PASS); // 刷新主线程任务,确保LiveData回调执行 Robolectric.flushForegroundThreadScheduler(); // 验证路线计算方法是否被正确调用 verify(mapRepository).calculateRoute(any(), eq("test-token"), any()); System.out.println("Finish Test"); } }
这种方式跳过了真实的网络请求,专注于验证你的业务逻辑是否正确,测试速度更快也更可靠。
内容的提问来源于stack exchange,提问作者Tlaloc-ES
相关产品推荐
相关产品推荐

