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

如何用Mockito测试Retrofit回调(MVP+Dagger2)及RecyclerView适配器变化

嘿,我来帮你搞定这个测试问题!你遇到的空指针大概率是因为测试环境里没正确初始化Presenter、Activity或者Mock网络服务,咱们一步步梳理正确的测试方案:

核心思路

要测试“成功下载Posts后RecyclerView适配器大小变化”,核心是用Mock服务模拟服务器的成功响应,让Presenter调用这个Mock服务,最后验证Activity里的RecyclerView适配器是否正确更新数据。咱们可以用Square的MockWebServer来模拟Retrofit的网络请求,配合Robolectric(用来模拟Android组件生命周期)或者Mockito(用来Mock依赖)来完成测试。

具体实现步骤

1. 先准备测试依赖

确保你的build.gradle(Module级)里添加了这些测试依赖:

testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.12.1'
testImplementation 'com.squareup.okhttp3:mockwebserver:4.11.0'
testImplementation 'com.google.code.gson:gson:2.10.1'
testImplementation 'org.mockito:mockito-core:5.6.0'

2. 初始化测试环境(解决空指针的关键)

在测试类的@Before方法里,要把所有需要的对象都初始化好:MockWebServer、指向Mock服务器的Retrofit实例、Presenter,以及模拟/启动的Activity。

public class PostsPresenterTest {
    private MockWebServer mockWebServer;
    private PostsApi postsApi;
    private PostsPresenter presenter;
    private MainActivity activity;

    @Before
    public void setup() throws IOException {
        // 初始化MockWebServer
        mockWebServer = new MockWebServer();
        mockWebServer.start();

        // 创建指向Mock服务器的Retrofit实例
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(mockWebServer.url("/"))
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        postsApi = retrofit.create(PostsApi.class);

        // 用Robolectric启动Activity,确保生命周期走到onCreate(初始化RecyclerView和适配器)
        activity = Robolectric.buildActivity(MainActivity.class)
                .create()
                .resume()
                .get();

        // 初始化Presenter,传入Mock的API和Activity作为View(假设Activity实现了PostsView接口)
        presenter = new PostsPresenter(postsApi, activity);
    }

    @After
    public void teardown() throws IOException {
        mockWebServer.shutdown();
    }
}

3. 编写测试方法

模拟服务器返回成功的Posts列表,触发Presenter的下载逻辑,最后验证适配器的大小:

@Test
public void fetchPosts_success_updatesRecyclerView() throws IOException {
    // 1. 准备模拟的Posts数据,转成JSON格式
    List<Post> mockPosts = Arrays.asList(
            new Post(1, "First Post", "This is my first post"),
            new Post(2, "Second Post", "This is my second post")
    );
    String mockResponseJson = new Gson().toJson(mockPosts);

    // 2. 让MockWebServer返回这个成功的JSON响应
    mockWebServer.enqueue(new MockResponse()
            .setResponseCode(200)
            .setBody(mockResponseJson)
            .addHeader("Content-Type", "application/json"));

    // 3. 触发Presenter的下载方法
    presenter.fetchPosts();

    // 4. 等待后台网络请求完成(Robolectric的方法,刷新线程调度器)
    Robolectric.flushBackgroundThreadScheduler();
    Robolectric.flushForegroundThreadScheduler();

    // 5. 验证RecyclerView适配器的itemCount是否和模拟数据一致
    RecyclerView recyclerView = activity.findViewById(R.id.posts_recycler_view);
    assertNotNull("RecyclerView适配器未初始化", recyclerView.getAdapter());
    assertEquals("适配器大小不符合预期", mockPosts.size(), recyclerView.getAdapter().getItemCount());
}
空指针的常见排查点

如果还是出现空指针,你可以检查这几点:

  • Activity的RecyclerView/适配器是否在onCreate里初始化:Robolectric的buildActivity().create()会触发onCreate,确保你的Activity在这里完成了RecyclerView和适配器的初始化。
  • Presenter的依赖是否注入正确:测试里的Presenter必须使用Mock的PostsApi,不能用生产环境的实例(否则会调用真实网络,导致空指针或超时)。
  • View接口方法是否正确实现:比如Presenter在下载完成后会调用activity.showPosts(List<Post>),这个方法里必须把数据设置给RecyclerView的适配器,否则适配器还是空的。

另外,如果你不想启动真实的Activity,也可以用Mockito MockPostsView接口,先验证Presenter是否正确调用了View的方法,再单独测试Activity的适配器更新逻辑:

// 用Mockito Mock View接口
private PostsView mockView = Mockito.mock(PostsView.class);

@Before
public void setup() throws IOException {
    mockWebServer = new MockWebServer();
    mockWebServer.start();
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(mockWebServer.url("/"))
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    postsApi = retrofit.create(PostsApi.class);
    presenter = new PostsPresenter(postsApi, mockView);
}

@Test
public void fetchPosts_success_callsShowPosts() throws IOException {
    List<Post> mockPosts = Arrays.asList(new Post(1, "Test Post", "Test Body"));
    String json = new Gson().toJson(mockPosts);
    mockWebServer.enqueue(new MockResponse().setBody(json).setResponseCode(200));

    presenter.fetchPosts();
    Robolectric.flushBackgroundThreadScheduler();

    // 验证Presenter调用了View的showPosts方法
    Mockito.verify(mockView).showPosts(mockPosts);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:20:57