首页 > 解决方案 > MockRestServiceServer 测试通过 Multipart-formdata 发送文件上传

问题描述

我有一种方法可以使用 multipart-formdata 向 api 发送休息请求,这会将文件上传到外部 api。但是,我无法为此完成单元测试方法。

我发现的第一个问题是,我期望的内容类型总是不同于该方法创建的内容类型。出于某种原因,在发送请求时,媒体类型是 multipart-formdata,但标头设置为除字符集和边界之外的标头。后者,边界,总是在改变它的值,因此我不能在单元测试中设置期望值,因为它总是不同的。

除此之外,我如何期望请求的内容与我启动测试的内容相同?我如何断言有效负载是相同的。

请检查代码:

服务等级:

@Service
@Slf4j
public class JiraService {

    private HttpHeaders createRequestHeaders(JiraClient jiraClient, MediaType contenType) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(contenType);
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        headers.setBasicAuth(jiraClient.getUsername(), jiraClient.getPassword());

        return headers;
    }

    private <EC, RC> ResponseEntity<RC> createRequestAndSend(HttpMethod method, String url, HttpHeaders headers,
            EC payload, Class<RC> responseType) {
        HttpEntity<EC> requestEntity = new HttpEntity<>(payload, headers);
        ResponseEntity<RC> responseEntity = restTemplate.exchange(url, method, requestEntity, responseType);
        // TODO deal with response

        log.error("Loggin something");

        return responseEntity;
    }

    public void addAttachment(JiraClient jiraClient, JiraIssue jiraIssue, JiraAttachment jiraAttachment)
            throws MalformedURLException, IOException {
        String url = jiraClient.getHost() + "/rest/api/2/issue/" + jiraIssue.getKey() + "/attachments";

        HttpHeaders headers = createRequestHeaders(jiraClient, MediaType.MULTIPART_FORM_DATA); // What to do here?
        headers.set("X-Atlassian-Token", "no-check");

        FileSystemResource file = jiraAttachment.downloadFileFromWeb();
        MultiValueMap<String, Object> payload = new LinkedMultiValueMap<>();
        payload.add("file", file);

        createRequestAndSend(HttpMethod.POST, url, headers, payload, String.class);

        jiraAttachment.deleteFileFromSystem();
    }
}

服务测试类


@ActiveProfiles("test")
@RestClientTest(JiraService.class)
public class JiraServiceTest {

  @Value("classpath:jira/add_attachment/validJiraAttachmentAddition.json")
  private Resource validJiraAttachmentAddition;

  @Autowired
  private MockRestServiceServer server;
  @Autowired
  private JiraService jiraService;

  @Mock
  private JiraAttachment mockJiraAttachment;

  private FileSystemResource attachmentFileSystemResource;

  @BeforeEach
  public void setupTests() throws IOException {
      // initialize mocks
  }

  @Test
  public void addAttachment_WithValidData_ShouldAddAttachmentToJiraIssue() throws Exception {
    String url = host + "/rest/api/2/issue/" + issueKey + "/attachments";

    ResponseActions stub = createServiceStub(HttpMethod.POST, url, MediaType.MULTIPART_FORM_DATA_VALUE);
    stub = stub.andExpect(header("X-Atlassian-Token", "no-check"));
    stub.andRespond(withSuccess());
    // How to assert that the content of the request is the same as the resource?

    when(mockJiraAttachment.downloadFileFromWeb()).thenReturn(attachmentFileSystemResource);

    jiraService.addAttachment(mockJiraClient, mockJiraIssue, mockJiraAttachment);
  }

  private ResponseActions createServiceStub(HttpMethod method, String url, String contenType) {
    String encodedCredentials = Base64.getEncoder().encodeToString((username + ":" + password).getBytes());

    ResponseActions stub = server.expect(ExpectedCount.once(), requestTo(url));
    stub = stub.andExpect(method(method));
    stub = stub.andExpect(header("Content-Type", contenType)); // How to expect the content type here ?
    stub = stub.andExpect(header("Authorization", "Basic " + encodedCredentials));

    return stub;
  }
}

标签: javaspringunit-testingmocking

解决方案


利用ContentRequestMatchers.contentTypeCompatibleWith(MediaType contentType)

import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
...

stub.andExpect(content().contentTypeCompatibleWith(MediaType.MULTIPART_FORM_DATA))

推荐阅读