Springを使用した複数のファイルアップロードテスト(複数のファイルとともに転送されたデータをDTOにバインド)


これはある企業が採用課題を解決する際に直面した問題である.
クライアントから複数の添付ファイルとタイトル、コンテンツ、日付などのデータを受信し、格納する必要がある要求を処理します.
以前にも同様の機能が実装されていたので,自信を持って実装を開始し,直ちにテストコードの作成を開始した.変なことはないと思っていたのに、エラーと2時間も戦った.

📌 エラー..。


リクエストを受信するAPIは以下の通りです.
    @PostMapping
    public ResponseEntity saveNotice(
            @RequestPart("notice") SaveNoticeDto saveNotice, @RequestPart(name = "file", required = false) List<MultipartFile> files)
    {
    	...
        
        return new ResponseEntity(HttpStatus.CREATED);
    }
public class SaveNoticeDto {

    private String title;
    private String content;
    private LocalDateTime endTime;
}
MultipartFormData受け入れ形態のために使用した@RequestPartMultipartFormData各セクションに名前と内容のタイプがあることが分かった.
そこで、上記コードテストをMockMvcとした場合、それをfileMockMultipartFile送信、SaveNoticeDto必要な値をDtoとしてJsonに変換し、MockPart送信を利用する.
    @DisplayName("POST /notices 공지사항 등록 API 테스트")
    @Test
    void saveNoticeApiTest() throws Exception {
        MockMultipartFile multipartFile1 = new MockMultipartFile("file", "test.txt", "text/plain", "test file".getBytes(StandardCharsets.UTF_8) );
        MockMultipartFile multipartFile2 = new MockMultipartFile("file", "test2.txt", "text/plain", "test file2".getBytes(StandardCharsets.UTF_8) );

        SaveNoticeDto noticeDto = new SaveNoticeDto("title1", "content1", LocalDateTime.now().plusDays(7));

        mockMvc.perform(multipart("/notices")
                .file(multipartFile1)
                .file(multipartFile2)
                .part(new MockPart("notice", noticeDtoJson.getBytes(StandardCharsets.UTF_8))).contentType(MediaType.APPLICATION_JSON)
        )
                .andDo(print())
                .andExpect(status().isCreated());
}
最初から描いたテストをそのままコードに移すことです.
実行結果に失敗しました...
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported]
初めて見たContent Typeに関するエラーが爆発したので、ここまでにしようと思います.
実際、以前は異なる方法で胃の機能を同じにしたことがある.
異なる形態で実施される位置決めについて
コトリンで表現されていますが、内容はほぼ同じです.
異なる点は、コントローラから他の値を取得する場合、DtoではなくStringなどの単一の値ですか?客体タイプとして受け取りました.
私は同じ方法で問題を解決することができますが、きっと...Dtoにバインドしたいです.

📌 解決!

    @DisplayName("POST /notices 공지사항 등록 API 테스트")
    @Test
    void saveNoticeApiTest() throws Exception {
        MockMultipartFile multipartFile1 = new MockMultipartFile("file", "test.txt", "text/plain", "test file".getBytes(StandardCharsets.UTF_8) );
        MockMultipartFile multipartFile2 = new MockMultipartFile("file", "test2.txt", "text/plain", "test file2".getBytes(StandardCharsets.UTF_8) );

        SaveNoticeDto noticeDto = new SaveNoticeDto("title1", "content1", LocalDateTime.now().plusDays(7));
        String noticeDtoJson = mapper.writeValueAsString(noticeDto);
        MockMultipartFile notice = new MockMultipartFile("notice", "notice", "application/json", noticeDtoJson.getBytes(StandardCharsets.UTF_8));

        mockMvc.perform(multipart("/notices")
                        .file(multipartFile1)
                        .file(multipartFile2)
                        .file(notice)
                )
                .andDo(print())
                .andExpect(status().isCreated())
                .andReturn();
    }
添付ファイルに用意したMultipartFileだけでなく、一緒に譲渡した価格もDtoになり、JsonになりMultipartFileになりました.