使用具有独立上下文和 SpringBoot 1.2.5 的 MockMvcBuilders 进行文件上传的单元测试
Unit Test of file upload using MockMvcBuilders with standalone context and SpringBoot 1.2.5
我正在使用 Spring Boot 1.2.5-RELEASE。我有一个控制器接收 MultipartFile
和 String
@RestController
@RequestMapping("file-upload")
public class MyRESTController {
@Autowired
private AService aService;
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseStatus(HttpStatus.CREATED)
public void fileUpload(
@RequestParam(value = "file", required = true) final MultipartFile file,
@RequestParam(value = "something", required = true) final String something) {
aService.doSomethingOnDBWith(file, value);
}
}
现在,该服务运行良好。我用 PostMan 测试了它,一切都按预期进行。
不幸的是,我无法为该代码编写独立的单元测试。当前单元测试是:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
public class ControllerTest{
MockMvc mockMvc;
@Mock
AService aService;
@InjectMocks
MyRESTController controller;
@Before public void setUp(){
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
public void testFileUpload() throws Exception{
final File file = getFileFromResource(fileName);
//File is correctly loaded
final MockMultipartFile multipartFile = new MockMultipartFile("aMultiPartFile.txt", new FileInputStream(file));
doNothing().when(aService).doSomethingOnDBWith(any(MultipartFile.class), any(String.class));
mockMvc.perform(
post("/file-upload")
.requestAttr("file", multipartFile.getBytes())
.requestAttr("something", ":(")
.contentType(MediaType.MULTIPART_FORM_DATA_VALUE))
.andExpect(status().isCreated());
}
}
测试失败
java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
现在,在 Spring 引导的 MultipartAutoConfiguration
class 中,我看到 MultipartResolver
是自动配置的。但是,我想使用 MockMvcBuilders
的 standaloneSetup
我无法访问它。
我尝试了几种单元测试配置,为简洁起见我没有报告。特别是,我还尝试了 here 所示的放心,但老实说这不起作用,因为我似乎无法模拟 AService
实例。
有什么解决办法吗?
您正在尝试将此处的单元测试 (standaloneSetup(controller).build();
) 与 Spring 集成测试 (@RunWith(SpringJUnit4ClassRunner.class)
) 结合起来。
做一个或另一个。
集成测试需要使用类似下面的代码。问题是伪造豆子。有一些方法可以使用 @Primary
注释和 @Profile
注释来伪造这样的 bean(您创建将覆盖主要生产 bean 的测试 bean)。我有一些这样伪造 Spring beans 的例子(例如 this bean is replaced by this bean in this test)。
@Autowired
private WebApplicationContext webApplicationContext;
@BeforeMethod
public void init() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
第二个选项是删除测试和测试控制器上的 @RunWith(SpringJUnit4ClassRunner.class)
和其他 class 级别配置,没有 Spring 独立设置的上下文。这样您就无法在控制器上测试验证注释,但可以使用 Spring MVC 注释。优点是可以通过 Mockito 伪造 bean(例如通过 InjectMocks 和 Mock 注释)
错误表明请求不是多部分请求。换句话说,到那时它应该已经被解析了。但是在 MockMvc 测试中没有实际请求。这只是模拟请求和响应。因此,您需要使用 perform.fileUpload(...) 来设置模拟文件上传请求。
我混合了 lkrnak 建议的内容和 Mockito @Spy
的功能。我使用 REST-Assured 来调用。所以,我做了如下:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
@IntegrationTest({"server.port:0"})
public class ControllerTest{
{
System.setProperty("spring.profiles.active", "unit-test");
}
@Autowired
@Spy
AService aService;
@Autowired
@InjectMocks
MyRESTController controller;
@Value("${local.server.port}")
int port;
@Before public void setUp(){
RestAssured.port = port;
MockitoAnnotations.initMocks(this);
}
@Test
public void testFileUpload() throws Exception{
final File file = getFileFromResource(fileName);
doNothing().when(aService)
.doSomethingOnDBWith(any(MultipartFile.class), any(String.class));
given()
.multiPart("file", file)
.multiPart("something", ":(")
.when().post("/file-upload")
.then().(HttpStatus.CREATED.value());
}
}
服务定义为
@Profile("unit-test")
@Primary
@Service
public class MockAService implements AService {
//empty methods implementation
}
我正在使用 Spring Boot 1.2.5-RELEASE。我有一个控制器接收 MultipartFile
和 String
@RestController
@RequestMapping("file-upload")
public class MyRESTController {
@Autowired
private AService aService;
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseStatus(HttpStatus.CREATED)
public void fileUpload(
@RequestParam(value = "file", required = true) final MultipartFile file,
@RequestParam(value = "something", required = true) final String something) {
aService.doSomethingOnDBWith(file, value);
}
}
现在,该服务运行良好。我用 PostMan 测试了它,一切都按预期进行。 不幸的是,我无法为该代码编写独立的单元测试。当前单元测试是:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
public class ControllerTest{
MockMvc mockMvc;
@Mock
AService aService;
@InjectMocks
MyRESTController controller;
@Before public void setUp(){
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
public void testFileUpload() throws Exception{
final File file = getFileFromResource(fileName);
//File is correctly loaded
final MockMultipartFile multipartFile = new MockMultipartFile("aMultiPartFile.txt", new FileInputStream(file));
doNothing().when(aService).doSomethingOnDBWith(any(MultipartFile.class), any(String.class));
mockMvc.perform(
post("/file-upload")
.requestAttr("file", multipartFile.getBytes())
.requestAttr("something", ":(")
.contentType(MediaType.MULTIPART_FORM_DATA_VALUE))
.andExpect(status().isCreated());
}
}
测试失败
java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
现在,在 Spring 引导的 MultipartAutoConfiguration
class 中,我看到 MultipartResolver
是自动配置的。但是,我想使用 MockMvcBuilders
的 standaloneSetup
我无法访问它。
我尝试了几种单元测试配置,为简洁起见我没有报告。特别是,我还尝试了 here 所示的放心,但老实说这不起作用,因为我似乎无法模拟 AService
实例。
有什么解决办法吗?
您正在尝试将此处的单元测试 (standaloneSetup(controller).build();
) 与 Spring 集成测试 (@RunWith(SpringJUnit4ClassRunner.class)
) 结合起来。
做一个或另一个。
集成测试需要使用类似下面的代码。问题是伪造豆子。有一些方法可以使用
@Primary
注释和@Profile
注释来伪造这样的 bean(您创建将覆盖主要生产 bean 的测试 bean)。我有一些这样伪造 Spring beans 的例子(例如 this bean is replaced by this bean in this test)。@Autowired private WebApplicationContext webApplicationContext; @BeforeMethod public void init() { mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); }
第二个选项是删除测试和测试控制器上的
@RunWith(SpringJUnit4ClassRunner.class)
和其他 class 级别配置,没有 Spring 独立设置的上下文。这样您就无法在控制器上测试验证注释,但可以使用 Spring MVC 注释。优点是可以通过 Mockito 伪造 bean(例如通过 InjectMocks 和 Mock 注释)
错误表明请求不是多部分请求。换句话说,到那时它应该已经被解析了。但是在 MockMvc 测试中没有实际请求。这只是模拟请求和响应。因此,您需要使用 perform.fileUpload(...) 来设置模拟文件上传请求。
我混合了 lkrnak 建议的内容和 Mockito @Spy
的功能。我使用 REST-Assured 来调用。所以,我做了如下:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
@IntegrationTest({"server.port:0"})
public class ControllerTest{
{
System.setProperty("spring.profiles.active", "unit-test");
}
@Autowired
@Spy
AService aService;
@Autowired
@InjectMocks
MyRESTController controller;
@Value("${local.server.port}")
int port;
@Before public void setUp(){
RestAssured.port = port;
MockitoAnnotations.initMocks(this);
}
@Test
public void testFileUpload() throws Exception{
final File file = getFileFromResource(fileName);
doNothing().when(aService)
.doSomethingOnDBWith(any(MultipartFile.class), any(String.class));
given()
.multiPart("file", file)
.multiPart("something", ":(")
.when().post("/file-upload")
.then().(HttpStatus.CREATED.value());
}
}
服务定义为
@Profile("unit-test")
@Primary
@Service
public class MockAService implements AService {
//empty methods implementation
}