Spring MVC 테스트를 사용하여 멀티 파트 POST 요청 단위 테스트


115

자동차 저장을 위해 다음 요청 처리기가 있습니다. 예를 들어 cURL을 사용할 때 이것이 작동하는지 확인했습니다. 이제 Spring MVC Test로 메서드를 단위 테스트하고 싶습니다. fileUploader를 사용하려고했지만 제대로 작동하지 않습니다. 또한 JSON 부분을 추가하지도 않습니다.

Spring MVC Test로이 메서드를 어떻게 단위 테스트 할 수 있습니까? 이에 대한 예를 찾을 수 없습니다.

@RequestMapping(value = "autos", method = RequestMethod.POST)
public ResponseEntity saveAuto(
    @RequestPart(value = "data") autoResource,
    @RequestParam(value = "files[]", required = false) List<MultipartFile> files) {
    // ...
}

자동 + 하나 이상의 파일에 대한 JSON 표현을 업로드하고 싶습니다.

정답에 현상금 100을 더하겠습니다!

답변:


256

이후 MockMvcRequestBuilders#fileUpload사용되지 않습니다, 당신은 사용할 수 있습니다 MockMvcRequestBuilders#multipart(String, Object...)을 반환합니다 MockMultipartHttpServletRequestBuilder. 그런 다음 여러 file(MockMultipartFile)통화를 연결하십시오.

다음은 작동하는 예입니다. 주어진@Controller

@Controller
public class NewController {

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    @ResponseBody
    public String saveAuto(
            @RequestPart(value = "json") JsonPojo pojo,
            @RequestParam(value = "some-random") String random,
            @RequestParam(value = "data", required = false) List<MultipartFile> files) {
        System.out.println(random);
        System.out.println(pojo.getJson());
        for (MultipartFile file : files) {
            System.out.println(file.getOriginalFilename());
        }
        return "success";
    }

    static class JsonPojo {
        private String json;

        public String getJson() {
            return json;
        }

        public void setJson(String json) {
            this.json = json;
        }

    }
}

및 단위 테스트

@WebAppConfiguration
@ContextConfiguration(classes = WebConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Example {

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Test
    public void test() throws Exception {

        MockMultipartFile firstFile = new MockMultipartFile("data", "filename.txt", "text/plain", "some xml".getBytes());
        MockMultipartFile secondFile = new MockMultipartFile("data", "other-file-name.data", "text/plain", "some other type".getBytes());
        MockMultipartFile jsonFile = new MockMultipartFile("json", "", "application/json", "{\"json\": \"someValue\"}".getBytes());

        MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        mockMvc.perform(MockMvcRequestBuilders.multipart("/upload")
                        .file(firstFile)
                        .file(secondFile)
                        .file(jsonFile)
                        .param("some-random", "4"))
                    .andExpect(status().is(200))
                    .andExpect(content().string("success"));
    }
}

그리고 @Configuration수업

@Configuration
@ComponentScan({ "test.controllers" })
@EnableWebMvc
public class WebConfig extends WebMvcConfigurationSupport {
    @Bean
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        return multipartResolver;
    }
}

테스트를 통과하고 결과를 제공해야합니다.

4 // from param
someValue // from json file
filename.txt // from first file
other-file-name.data // from second file

주의 할 점은 다른 콘텐츠 유형을 제외하고는 다른 멀티 파트 파일과 마찬가지로 JSON을 전송한다는 것입니다.


1
안녕하세요 Sotirios, 저는 그 아름다운 예를보고 기뻤습니다. 그리고 그것을 제공 한 사람이 누구인지, 빙고! Sotirios였습니다! 테스트는 정말 멋지게 만듭니다. 나는 나를 괴롭히는 한 가지가 있는데, 요청이 여러 부분 (500)이 아니라고 불평합니다.
Stephane 2014 년

이 주장이 실패하는 것은 assertIsMultipartRequest (servletRequest); CommonsMultipartResolver가 구성되지 않은 것 같습니다. 하지만 내 빈의 로거가 로그에 표시됩니다.
Stephane

@shredding 멀티 파트 파일과 모델 객체를 json으로 컨트롤러에 보내는 데이 접근 방식을 사용했습니다. 하지만 MethodArgumentConversionNotSupportedException컨트롤러를 치면 모델 객체가 던집니다. 여기에서 놓친 단계가 있습니까? - stackoverflow.com/questions/50953227/...
브라이언 J

1
이 예는 저에게 많은 도움이되었습니다. 감사합니다
kiranNswamy

multipart는 POST 방법을 사용합니다. 누구든지이 예제를 제공 할 수 있지만 PATCH 방법을 사용합니까?
lalilulelo_1986

16

스프링 MVC 쇼케이스에서 가져온이 예제를 살펴보십시오. 이것은 소스 코드에 대한 링크입니다 .

@RunWith(SpringJUnit4ClassRunner.class)
public class FileUploadControllerTests extends AbstractContextControllerTests {

    @Test
    public void readString() throws Exception {

        MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes());

        webAppContextSetup(this.wac).build()
            .perform(fileUpload("/fileupload").file(file))
            .andExpect(model().attribute("message", "File 'orig' uploaded successfully"));
    }

}

1
fileUpload대신 사용되지 않습니다 multipart(String, Object...).
naXa

14

이 메서드 MockMvcRequestBuilders.fileUpload는 더 이상 사용되지 않습니다 MockMvcRequestBuilders.multipart.

다음은 예입니다.

import static org.hamcrest.CoreMatchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.multipart.MultipartFile;


/**
 * Unit test New Controller.
 *
 */
@RunWith(SpringRunner.class)
@WebMvcTest(NewController.class)
public class NewControllerTest {

    private MockMvc mockMvc;

    @Autowired
    WebApplicationContext wContext;

    @MockBean
    private NewController newController;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wContext)
                   .alwaysDo(MockMvcResultHandlers.print())
                   .build();
    }

   @Test
    public void test() throws Exception {
       // Mock Request
        MockMultipartFile jsonFile = new MockMultipartFile("test.json", "", "application/json", "{\"key1\": \"value1\"}".getBytes());

        // Mock Response
        NewControllerResponseDto response = new NewControllerDto();
        Mockito.when(newController.postV1(Mockito.any(Integer.class), Mockito.any(MultipartFile.class))).thenReturn(response);

        mockMvc.perform(MockMvcRequestBuilders.multipart("/fileUpload")
                .file("file", jsonFile.getBytes())
                .characterEncoding("UTF-8"))
        .andExpect(status().isOk());

    }

}

2

여기 나를 위해 일한 것이 있습니다. 여기서 테스트중인 EmailController에 파일을 첨부합니다. 또한 데이터를 게시하는 방법에 대한 우편 배달부 스크린 샷을 살펴보십시오.

    @WebAppConfiguration
    @RunWith(SpringRunner.class)
    @SpringBootTest(
            classes = EmailControllerBootApplication.class
        )
    public class SendEmailTest {

        @Autowired
        private WebApplicationContext webApplicationContext;

        @Test
        public void testSend() throws Exception{
            String jsonStr = "{\"to\": [\"email.address@domain.com\"],\"subject\": "
                    + "\"CDM - Spring Boot email service with attachment\","
                    + "\"body\": \"Email body will contain  test results, with screenshot\"}";

            Resource fileResource = new ClassPathResource(
                    "screen-shots/HomePage-attachment.png");

            assertNotNull(fileResource);

            MockMultipartFile firstFile = new MockMultipartFile( 
                       "attachments",fileResource.getFilename(),
                        MediaType.MULTIPART_FORM_DATA_VALUE,
                        fileResource.getInputStream());  
                        assertNotNull(firstFile);


            MockMvc mockMvc = MockMvcBuilders.
                  webAppContextSetup(webApplicationContext).build();

            mockMvc.perform(MockMvcRequestBuilders
                   .multipart("/api/v1/email/send")
                    .file(firstFile)
                    .param("data", jsonStr))
                    .andExpect(status().is(200));
            }
        }

우편 배달부 요청


귀하의 답변이 저에게도 도움이되었습니다. @Alfred
Parameshwar

1

Spring4 / SpringBoot 1.x를 사용하는 경우 "text"(json) 부분도 추가 할 수 있음을 언급 할 가치가 있습니다. MockMvcRequestBuilders.fileUpload (). file (MockMultipartFile 파일)을 통해 수행 할 수 있습니다 ( .multipart()이 버전에서는 메서드 를 사용할 수 없으므로 필요함 ).

@Test
public void test() throws Exception {

   mockMvc.perform( 
       MockMvcRequestBuilders.fileUpload("/files")
         // file-part
         .file(makeMultipartFile( "file-part" "some/path/to/file.bin", "application/octet-stream"))
        // text part
         .file(makeMultipartTextPart("json-part", "{ \"foo\" : \"bar\" }", "application/json"))
       .andExpect(status().isOk())));

   }

   private MockMultipartFile(String requestPartName, String filename, 
       String contentType, String pathOnClassPath) {

       return new MockMultipartFile(requestPartName, filename, 
          contentType, readResourceFile(pathOnClasspath);
   }

   // make text-part using MockMultipartFile
   private MockMultipartFile makeMultipartTextPart(String requestPartName, 
       String value, String contentType) throws Exception {

       return new MockMultipartFile(requestPartName, "", contentType,
               value.getBytes(Charset.forName("UTF-8")));   
   }


   private byte[] readResourceFile(String pathOnClassPath) throws Exception {
      return Files.readAllBytes(Paths.get(Thread.currentThread().getContextClassLoader()
         .getResource(pathOnClassPath).toUri()));
   }

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.