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
相关产品推荐
相关产品推荐

