任何人都可以为这段代码建议一个 mockito 测试吗?
Can anyone suggest a mockito Test for this code?
此函数尝试使用 GitHub API 检索 GitHub 存储库名称的主题:https://api.github.com/repos/flutter/flutter/topics
public List<String> getTopics(SearchRepository searchRepository){
GitHubRequest request = new GitHubRequest();
List<String> topic_list = new ArrayList<>();
try {
String url = searchRepository.getUrl().split("//")[1].split("github.com")[1];
request.setUri("/repos"+ url + "/topics");
String result = new BufferedReader(new InputStreamReader(gitHubClient.getStream(request)))
.lines().collect(Collectors.joining("\n"));
JSONObject jsonObject = new JSONObject(result);
topic_list = Arrays.stream(jsonObject.get("names").toString().replace("[", "").replace("]", "").split(",")).collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
}
return topic_list;
}
字符串到列表转换前返回的url是:https://github.com/repouser/reponame
SearchRepository 是软件包中 Repository 的 v2 模型 class:
SearchRepositroy
根据这个精彩社区答案的早期建议(虽然问题现在已被编辑,但它仍然相关)我创建了模拟测试来测试上述功能,如下所示:
@Test
public void getTopicsTest() throws IOException{
SearchRepository mocksearchRepository = mock(SearchRepository.class);
GitHubClient mockClient = mock(GitHubClient.class);
GitHubRequest mockRequest = mock(GitHubRequest.class);
when(mocksearchRepository.getUrl()).thenReturn("https://github.com/mockuser/mockrepo");
when(mocksearchRepository.getName()).thenReturn("mockrepo");
when(mocksearchRepository.getOwner()).thenReturn("mockuser");
//when(mockRequest.setUri((String) any())).thenReturn(mockRequest.setUri("/repo/mockuser/mockrepo/topics"));
//The format of the return form is: https://github.com/CyC2018/CS-Notes
when(mockClient.getStream(any())).thenReturn(topicInputStream());
//SearchRepository querySearch = new SearchRepository("mockuser","mockrepo");
List<String> topics = githubServiceMock.getTopics(mocksearchRepository);
System.out.println(topics);
}
private InputStream topicInputStream() {
String mockTopics = "{" +
"topic1\": [" +
"topic2\"," +
"topic3\"," +
"skia" +
"]" +
"}";
InputStream stream = new ByteArrayInputStream(mockTopics.getBytes(StandardCharsets.UTF_8));
System.out.println(stream);
return stream;
}
但是,由于函数中的 request.setUri(Uri(String)),我得到 404 内部服务器错误异常。请指出我哪里出错了。
Test services.GithubServiceTest.getTopicsTest started
java.io.ByteArrayInputStream@6ed99482
org.eclipse.egit.github.core.client.RequestException: Not Found (404)
| => rat org.eclipse.egit.github.core.client.GitHubClient.createException(GitHubClient.java:552)
at org.eclipse.egit.github.core.client.GitHubClient.getResponseStream(GitHubClient.java:701)
at org.eclipse.egit.github.core.client.GitHubClient.getStream(GitHubClient.java:667)
at services.GithubService.getTopics(GithubService.java:231)
at services.GithubServiceTest.getTopicsTest(GithubServiceTest.java:222)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:79)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at com.novocode.junit.JUnitRunner.execute(JUnitRunner.java:132)
at sbt.ForkMain$Run.lambda$runTest(ForkMain.java:413)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
[]
[info] Test services.GithubServiceTest.getIssueWordLevelStatisticsTest started
[info] Test services.GithubServiceTest.getRepositoriesByTopicTest started
[info] Test services.GithubServiceTest.getUserDetailsTest started
[info] Test services.GithubServiceTest.getRepositoryDetailsTest started
[info] Test run finished: 0 failed, 0 ignored, 5 total, 1.122s
[error] Failed: Total 10, Failed 1, Errors 0, Passed 9
[error] Failed tests:
[error] controllers.GithubControllerTest
[error] (Test / test) sbt.TestsFailedException: Tests unsuccessful
您可以模拟 repositoryService
和 gitHubClient
来测试各种场景。
您可以为这些字段提供包级别 setter。用 Guava VisibleForTesting 注解来注解是个好主意。
然后你需要在对实例进行实际测试之前设置模拟。
模拟伪代码
// First, we mock repository so we can return it from service
Repository repositoryMock = mock(Repository.class);
when(repository.getUrl()).thenReturn("https://...."); // You can return a URL or String, according to the mocked method's return type
// Then, we mock RepositoryService as well
RepositoryService repositoryServiceMock = mock(RepositoryService.class);
when(repositoryServiceMock.getRepository(anyString(), anyString()).thenReturn(repositoryMock);
// We mock gitHubService similarly
...
// After setting mock on the instance, we call the method and see if the results are expected
List<String> topics = getTopics("...", "...");
assertEquals(topics, ...);
// You can also assert interaction related things
verify(repositoryService).getRepository("a", "b"); // This is OK only if the service is called with "a" and "b" arguments
首先,您需要将模拟对象 (repositoryService,gitHubClient) 注入到您的函数中。
如果使用spring/spring引导,可以考虑使用@Mock和@MockBean注解。
模拟必要的 bean。
以下代码手动创建模拟对象。
RepositoryService fakeRs = Mockito.mock(RepositoryService.class);
GitHubClient fakeGHC = Mockito.mock(GitHubClient.class);
您也可以使用setter 方法来设置模拟对象。
setRepositoryService(fakeRs);
setGitHubClient(fakeGHC);
另一种方法是使用反射实用程序设置私有对象。
ReflectionTestUtils.setField(yourService, "repositoryService", fakeRs);
ReflectionTestUtils.setField(yourService, "gitHubClient", fakeGHC);
提取完模拟对象后,您可以从模拟对象中编写预期 behavior/data 的测试。
@Test
public void testGetTopics(){
// init mock object code in case setter/getter/reflection utils
Repository expectedRepository = createExampleRepository();
Mockito.when(repositoryService.getRepository(Mockito.anyString(),Mockito.anyString())
.thenReturn(expectedRepository);
// continue to fake gitHubClient with your expected data/ exceptions...
//call your method
List<?> data = yourService.getTopic("user","data");
Assertions.assertTrue(data!=null);
// you can write few assertion base on your fake datas
}
PS:不要copy/paste代码,你会得到编译错误。我没有使用编辑器工具。
此函数尝试使用 GitHub API 检索 GitHub 存储库名称的主题:https://api.github.com/repos/flutter/flutter/topics
public List<String> getTopics(SearchRepository searchRepository){
GitHubRequest request = new GitHubRequest();
List<String> topic_list = new ArrayList<>();
try {
String url = searchRepository.getUrl().split("//")[1].split("github.com")[1];
request.setUri("/repos"+ url + "/topics");
String result = new BufferedReader(new InputStreamReader(gitHubClient.getStream(request)))
.lines().collect(Collectors.joining("\n"));
JSONObject jsonObject = new JSONObject(result);
topic_list = Arrays.stream(jsonObject.get("names").toString().replace("[", "").replace("]", "").split(",")).collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
}
return topic_list;
}
字符串到列表转换前返回的url是:https://github.com/repouser/reponame
SearchRepository 是软件包中 Repository 的 v2 模型 class: SearchRepositroy 根据这个精彩社区答案的早期建议(虽然问题现在已被编辑,但它仍然相关)我创建了模拟测试来测试上述功能,如下所示:
@Test
public void getTopicsTest() throws IOException{
SearchRepository mocksearchRepository = mock(SearchRepository.class);
GitHubClient mockClient = mock(GitHubClient.class);
GitHubRequest mockRequest = mock(GitHubRequest.class);
when(mocksearchRepository.getUrl()).thenReturn("https://github.com/mockuser/mockrepo");
when(mocksearchRepository.getName()).thenReturn("mockrepo");
when(mocksearchRepository.getOwner()).thenReturn("mockuser");
//when(mockRequest.setUri((String) any())).thenReturn(mockRequest.setUri("/repo/mockuser/mockrepo/topics"));
//The format of the return form is: https://github.com/CyC2018/CS-Notes
when(mockClient.getStream(any())).thenReturn(topicInputStream());
//SearchRepository querySearch = new SearchRepository("mockuser","mockrepo");
List<String> topics = githubServiceMock.getTopics(mocksearchRepository);
System.out.println(topics);
}
private InputStream topicInputStream() {
String mockTopics = "{" +
"topic1\": [" +
"topic2\"," +
"topic3\"," +
"skia" +
"]" +
"}";
InputStream stream = new ByteArrayInputStream(mockTopics.getBytes(StandardCharsets.UTF_8));
System.out.println(stream);
return stream;
}
但是,由于函数中的 request.setUri(Uri(String)),我得到 404 内部服务器错误异常。请指出我哪里出错了。
Test services.GithubServiceTest.getTopicsTest started
java.io.ByteArrayInputStream@6ed99482
org.eclipse.egit.github.core.client.RequestException: Not Found (404)
| => rat org.eclipse.egit.github.core.client.GitHubClient.createException(GitHubClient.java:552)
at org.eclipse.egit.github.core.client.GitHubClient.getResponseStream(GitHubClient.java:701)
at org.eclipse.egit.github.core.client.GitHubClient.getStream(GitHubClient.java:667)
at services.GithubService.getTopics(GithubService.java:231)
at services.GithubServiceTest.getTopicsTest(GithubServiceTest.java:222)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:79)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at com.novocode.junit.JUnitRunner.execute(JUnitRunner.java:132)
at sbt.ForkMain$Run.lambda$runTest(ForkMain.java:413)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
[]
[info] Test services.GithubServiceTest.getIssueWordLevelStatisticsTest started
[info] Test services.GithubServiceTest.getRepositoriesByTopicTest started
[info] Test services.GithubServiceTest.getUserDetailsTest started
[info] Test services.GithubServiceTest.getRepositoryDetailsTest started
[info] Test run finished: 0 failed, 0 ignored, 5 total, 1.122s
[error] Failed: Total 10, Failed 1, Errors 0, Passed 9
[error] Failed tests:
[error] controllers.GithubControllerTest
[error] (Test / test) sbt.TestsFailedException: Tests unsuccessful
您可以模拟 repositoryService
和 gitHubClient
来测试各种场景。
您可以为这些字段提供包级别 setter。用 Guava VisibleForTesting 注解来注解是个好主意。
然后你需要在对实例进行实际测试之前设置模拟。
模拟伪代码
// First, we mock repository so we can return it from service
Repository repositoryMock = mock(Repository.class);
when(repository.getUrl()).thenReturn("https://...."); // You can return a URL or String, according to the mocked method's return type
// Then, we mock RepositoryService as well
RepositoryService repositoryServiceMock = mock(RepositoryService.class);
when(repositoryServiceMock.getRepository(anyString(), anyString()).thenReturn(repositoryMock);
// We mock gitHubService similarly
...
// After setting mock on the instance, we call the method and see if the results are expected
List<String> topics = getTopics("...", "...");
assertEquals(topics, ...);
// You can also assert interaction related things
verify(repositoryService).getRepository("a", "b"); // This is OK only if the service is called with "a" and "b" arguments
首先,您需要将模拟对象 (repositoryService,gitHubClient) 注入到您的函数中。
如果使用spring/spring引导,可以考虑使用@Mock和@MockBean注解。 模拟必要的 bean。
以下代码手动创建模拟对象。
RepositoryService fakeRs = Mockito.mock(RepositoryService.class);
GitHubClient fakeGHC = Mockito.mock(GitHubClient.class);
您也可以使用setter 方法来设置模拟对象。 setRepositoryService(fakeRs); setGitHubClient(fakeGHC);
另一种方法是使用反射实用程序设置私有对象。
ReflectionTestUtils.setField(yourService, "repositoryService", fakeRs);
ReflectionTestUtils.setField(yourService, "gitHubClient", fakeGHC);
提取完模拟对象后,您可以从模拟对象中编写预期 behavior/data 的测试。
@Test
public void testGetTopics(){
// init mock object code in case setter/getter/reflection utils
Repository expectedRepository = createExampleRepository();
Mockito.when(repositoryService.getRepository(Mockito.anyString(),Mockito.anyString())
.thenReturn(expectedRepository);
// continue to fake gitHubClient with your expected data/ exceptions...
//call your method
List<?> data = yourService.getTopic("user","data");
Assertions.assertTrue(data!=null);
// you can write few assertion base on your fake datas
}
PS:不要copy/paste代码,你会得到编译错误。我没有使用编辑器工具。