Использование Spring MVC Test для unit test многостраничного запроса POST - программирование
Подтвердить что ты не робот

Использование Spring MVC Test для unit test многостраничного запроса POST

У меня есть следующий обработчик запросов для сохранения авто. Я убедился, что это работает, когда я использую, например, завиток. Теперь я хочу протестировать метод с помощью 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 в награду за правильный ответ!

4b9b3361

Ответ 1

Поскольку MockMvcRequestBuilders#fileUpload устарела, вы можете использовать MockMvcRequestBuilders#multipart(String, Object...) который возвращает MockMultipartHttpServletRequestBuilder. Затем file(MockMultipartFile) вызовов 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 точно так же, как и любой другой многокомпонентный файл, за исключением другого типа контента.

Ответ 2

Посмотрите на этот пример, взятый из витрины spring 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"));
    }

}

Ответ 3

Метод 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());

    }

}

Ответ 4

Если вы используете Spring4/SpringBoot 1.x, то стоит упомянуть, что вы также можете добавлять "текстовые" (json) части. Это можно сделать с помощью файла MockMvcRequestBuilders.fileUpload(). (Файл 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()));
   }

}