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

如何用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()中使用?

  1. Promise
  2. metadataClient.getPriorities() 返回 Promise<Iterable>
  3. metadataClient.getPriorities().claim() 返回 Iterable
  4. metadataClient.getIssueTypes() 返回 Promise<Iterable>
  5. metadataClient.getIssueTypes().claim() 返回 Iterable
  6. metadataClient.getFields() 返回 Promise<Iterable>
  7. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 02:10:32