如何用Mockito模拟JIRA Java客户端的各类对象及返回值?
JIRA集成与Mockito单元测试模拟问题
背景
我们正在将应用与JIRA集成,以实现创建带附件的问题功能。
方法1:创建JIRA问题
public JSONObject createIssue() { IssueRestClient issueClient = restClient.getIssueClient(); MetadataRestClient metadataClient = restClient.getMetadataClient(); Map<String, Long> priorityMap = new HashMap<>(); Map<String, Long> issueMap = new HashMap<>(); Map<String, String> fieldsMap = new HashMap<>(); // 获取所有优先级类型列表 metadataClient.getPriorities().claim().forEach(priorityType -> priorityMap.put(priorityType.getName(), priorityType.getId())); // 获取所有问题类型列表 metadataClient.getIssueTypes().claim().forEach(issueType -> issueMap.put(issueType.getName(), issueType.getId())); // 获取所有字段列表(包含自定义字段) metadataClient.getFields().claim().forEach(fieldType -> fieldsMap.put(fieldType.getName(), fieldType.getId())); // 省略剩余代码 }
方法2:为问题添加附件
public void addAttachmentToIssue(String issueId, InputStream inputStream, String fileNameWithExtension) { Issue issue = null; IssueRestClient issueClient = restClient.getIssueClient(); Promise<Issue> promiseIssue = issueClient.getIssue(issueId); issue = promiseIssue.claim(); issueClient.addAttachment(issue.getAttachmentsUri(), inputStream, fileNameWithExtension); }
现有单元测试代码
public class JIRATest{ @InjectMocks JIRAService mockJiraService; JiraRestClient mockJiraRestClient; IssueRestClient mockIssueRestClient; Promise mockPromise; Issue mockIssue; @BeforeEach public void setup() { mockJiraService = new JIRAService(); mockJiraRestClient = mock(JiraRestClient.class); mockIssueRestClient = mock(IssueRestClient.class); mockJiraService.setRestClient(mockJiraRestClient); mockPromise = mock(Promise.class); mockIssue = mock(Issue.class); } @Test public void addAttachmentTest() throws MalformedURLException, IOException { Mockito.when(mockJiraRestClient.getIssueClient()).thenReturn(mockIssueRestClient); Mockito.when(mockIssueRestClient.getIssue("DCU")).thenReturn(mockPromise); Mockito.when(mockPromise.claim()).thenReturn(mockIssue); Mockito.when(mockIssueRestClient.addAttachment(any(), any(), any())); String webSite = "https://www.google.com"; URL url = new URL(webSite); InputStream stream = url.openStream(); mockJiraService.addAttachmentToIssue("issueId", stream, "lowes-webpage.html"); } }
需要解决的模拟需求
请问如何模拟以下对象,以便在Mockito的thenReturn()中使用?
- Promise
- metadataClient.getPriorities() 返回 Promise<Iterable
> - metadataClient.getPriorities().claim() 返回 Iterable
- metadataClient.getIssueTypes() 返回 Promise<Iterable
> - metadataClient.getIssueTypes().claim() 返回 Iterable
- metadataClient.getFields() 返回 Promise<Iterable
> - metadataClient.getFields().claim() 返回 Iterable
模拟实现方案
针对上述需求,直接按以下方式用Mockito实现模拟:
1. 模拟Promise<Issue>
直接创建泛型mock对象:
// 在测试类的setup或测试方法中定义 Promise<Issue> mockIssuePromise = mock(Promise.class); // 关联到IssueRestClient的调用 when(mockIssueRestClient.getIssue(anyString())).thenReturn(mockIssuePromise); // 让claim()返回已mock的Issue对象 when(mockIssuePromise.claim()).thenReturn(mockIssue);
2. 模拟metadataClient.getPriorities()返回Promise<Iterable<Priority>>
先mockMetadataRestClient,再创建对应的Promise mock:
MetadataRestClient mockMetadataClient = mock(MetadataRestClient.class); Promise<Iterable<Priority>> mockPriorityPromise = mock(Promise.class); // 关联到JiraRestClient的调用 when(mockJiraRestClient.getMetadataClient()).thenReturn(mockMetadataClient); when(mockMetadataClient.getPriorities()).thenReturn(mockPriorityPromise);
3. 模拟metadataClient.getPriorities().claim()返回Iterable<Priority>
构造mock的Priority列表,让Promise的claim()返回该列表:
// 创建两个mock的Priority对象 Priority mockHighPriority = mock(Priority.class); Priority mockMediumPriority = mock(Priority.class); // 设置必要的属性返回值 when(mockHighPriority.getName()).thenReturn("高优先级"); when(mockHighPriority.getId()).thenReturn(1L); when(mockMediumPriority.getName()).thenReturn("中优先级"); when(mockMediumPriority.getId()).thenReturn(2L); // 组装成Iterable集合 Iterable<Priority> mockPriorities = Arrays.asList(mockHighPriority, mockMediumPriority); // 关联到Promise的claim()方法 when(mockPriorityPromise.claim()).thenReturn(mockPriorities);
4. 模拟metadataClient.getIssueTypes()返回Promise<Iterable<IssueType>>
和优先级的模拟逻辑一致:
Promise<Iterable<IssueType>> mockIssueTypePromise = mock(Promise.class); when(mockMetadataClient.getIssueTypes()).thenReturn(mockIssueTypePromise);
5. 模拟metadataClient.getIssueTypes().claim()返回Iterable<IssueType>
构造mock的IssueType列表:
IssueType mockBugType = mock(IssueType.class); IssueType mockTaskType = mock(IssueType.class); when(mockBugType.getName()).thenReturn("Bug"); when(mockBugType.getId()).thenReturn(10000L); when(mockTaskType.getName()).thenReturn("任务"); when(mockTaskType.getId()).thenReturn(10001L); Iterable<IssueType> mockIssueTypes = Arrays.asList(mockBugType, mockTaskType); when(mockIssueTypePromise.claim()).thenReturn(mockIssueTypes);
6. 模拟metadataClient.getFields()返回Promise<Iterable<Field>>
同样创建对应的Promise mock:
Promise<Iterable<Field>> mockFieldPromise = mock(Promise.class); when(mockMetadataClient.getFields()).thenReturn(mockFieldPromise);
7. 模拟metadataClient.getFields().claim()返回Iterable<Field>
构造包含系统字段和自定义字段的mock列表:
Field mockSummaryField = mock(Field.class); Field mockCustomField = mock(Field.class); when(mockSummaryField.getName()).thenReturn("摘要"); when(mockSummaryField.getId()).thenReturn("summary"); when(mockCustomField.getName()).thenReturn("自定义字段"); when(mockCustomField.getId()).thenReturn("customfield_10005"); Iterable<Field> mockFields = Arrays.asList(mockSummaryField, mockCustomField); when(mockFieldPromise.claim()).thenReturn(mockFields);
将上述代码整合到测试类的setup()方法或对应测试方法中,即可完成所有对象的模拟。
内容的提问来源于stack exchange,提问作者Vishnu
相关产品推荐
相关产品推荐

