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

Mockito测试GitHub仓库getTopics方法运行报404错误求助

问题根因
  • 模拟的GitHubClient未注入业务服务:你在测试中创建了mockClient,但没有将这个模拟实例替换掉GithubService内部持有的真实gitHubClient实例,导致业务代码运行时调用了真实客户端发起网络请求,触发404报错。
  • 模拟的GitHubRequest无意义:业务代码中是直接new GitHubRequest()创建实例,测试中mock的mockRequest根本不会被业务代码用到,属于无效代码。
  • 模拟返回的JSON格式错误:GitHub获取仓库主题的接口返回的根节点字段是names,你构造的mockTopics不仅字段名错误,还存在引号不配对的语法问题,就算接口调用成功,后续JSON解析也会抛出异常。
修正后的测试代码
@RunWith(MockitoJUnitRunner.class)
public class GithubServiceTest {
    // 自动注入mock依赖的待测试服务实例
    @InjectMocks
    private GithubService githubServiceMock;

    // 会自动注入到上面@InjectMocks修饰的实例中
    @Mock
    private GitHubClient gitHubClient;

    @Test
    public void getTopicsTest() throws IOException{
        SearchRepository mockSearchRepository = mock(SearchRepository.class);
        when(mockSearchRepository.getUrl()).thenReturn("https://github.com/mockuser/mockrepo");
        
        // 模拟GitHubClient返回构造好的主题数据流
        when(gitHubClient.getStream(any(GitHubRequest.class))).thenReturn(topicInputStream());
        
        List<String> topics = githubServiceMock.getTopics(mockSearchRepository);
        // 验证返回结果正确性
        assertEquals(Arrays.asList("topic2", "topic3", "skia"), topics);
    }

    private InputStream topicInputStream() {
        // 按照GitHub官方接口返回格式构造合法JSON
        String mockTopics = "{\"names\": [\"topic2\",\"topic3\",\"skia\"]}";
        return new ByteArrayInputStream(mockTopics.getBytes(StandardCharsets.UTF_8));
    }
}

如果你的GithubService是通过构造函数传入GitHubClient,也可以直接在测试中手动创建实例:

// 无需@InjectMocks和@Mock注解的写法
@Test
public void getTopicsTest() throws IOException{
    SearchRepository mockSearchRepository = mock(SearchRepository.class);
    when(mockSearchRepository.getUrl()).thenReturn("https://github.com/mockuser/mockrepo");
    GitHubClient mockClient = mock(GitHubClient.class);
    when(mockClient.getStream(any(GitHubRequest.class))).thenReturn(topicInputStream());
    // 手动构造服务实例传入mockClient
    GithubService githubService = new GithubService(mockClient);
    
    List<String> topics = githubService.getTopics(mockSearchRepository);
    assertEquals(Arrays.asList("topic2", "topic3", "skia"), topics);
}
额外优化建议

你的业务代码中通过拆分URL获取仓库所有者和名称的方式稳定性较低,可直接使用SearchRepository自带的getOwner()和getName()方法拼接请求路径,避免URL格式异常导致的问题:

// 替换原来的URL拆分逻辑
request.setUri("/repos/" + searchRepository.getOwner() + "/" + searchRepository.getName() + "/topics");

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 02:06:08