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

如何让单元测试等待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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:30:45