在独立的 MockMvc 中测试 @Validated RestController 不工作
Testing @Validated RestController in standalone MockMvc not working
我用 @Validated 注释了 RestController 以验证路径变量/请求参数:
@RestController
@Validated
public class MainController implements ApplicationListener<ApplicationReadyEvent> {
@Autowired
private CarsService carsService;
@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleException(ConstraintViolationException ex) {}
@GetMapping(
value = "/",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> getCars(
@RequestParam(value = "offset", defaultValue = "0") @PositiveOrZero
Integer offset,
@RequestParam(value = "limit", defaultValue = paginationLimitDefault)
@Positive @Max(paginationLimitMax)
Integer limit) {
...
...
Map responseBody = new HashMap<String, Object>();
responseBody.put("offset", offset);
responseBody.put("limit", limit);
return ResponseEntity.status(HttpStatus.OK).body(responseBody);
}
}
现在,我想使用独立的 mockMvc 对控制器级别进行单元测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class TestMainController {
@InjectMocks
private MainController mainController;
@Mock
private CarsService carsServiceMock;
private MockMvc mockMvc;
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(mainController).build();
}
@Test
public void getCarsInvalidOffset() throws Exception {
mockMvc.perform(get("/")
.param("offset", "-1"))
.andExpect(status().isBadRequest());
}
@Test
public void getCarsInvalidLimit() throws Exception {
mockMvc.perform(get("/")
.param("limit", "0"))
.andExpect(status().isBadRequest());
mockMvc.perform(get("/")
.param("limit", "-1"))
.andExpect(status().isBadRequest());
mockMvc.perform(get("/")
.param("limit", "101"))
.andExpect(status().isBadRequest());
}
}
问题是使用无效参数的测试(上面代码片段中的两个测试)应该有 return 错误的请求,实际上 returning 200 OK 结果测试失败。
我该如何解决?
谢谢
我怀疑是因为您在模拟 MainController,所以 @Validated 没有生效。试试这个:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class TestMainController {
@Autowired
private MainController mainController;
@MockBean
private CarsService carsServiceMock;
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@Before
public void initMocks() {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.build();
}
独立设置无法做到这一点。
更多详情请参考:
对于@Validated 测试用例,我们需要:
MockMvcBuilders.webAppContextSetup()
我用 @Validated 注释了 RestController 以验证路径变量/请求参数:
@RestController
@Validated
public class MainController implements ApplicationListener<ApplicationReadyEvent> {
@Autowired
private CarsService carsService;
@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleException(ConstraintViolationException ex) {}
@GetMapping(
value = "/",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> getCars(
@RequestParam(value = "offset", defaultValue = "0") @PositiveOrZero
Integer offset,
@RequestParam(value = "limit", defaultValue = paginationLimitDefault)
@Positive @Max(paginationLimitMax)
Integer limit) {
...
...
Map responseBody = new HashMap<String, Object>();
responseBody.put("offset", offset);
responseBody.put("limit", limit);
return ResponseEntity.status(HttpStatus.OK).body(responseBody);
}
}
现在,我想使用独立的 mockMvc 对控制器级别进行单元测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class TestMainController {
@InjectMocks
private MainController mainController;
@Mock
private CarsService carsServiceMock;
private MockMvc mockMvc;
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(mainController).build();
}
@Test
public void getCarsInvalidOffset() throws Exception {
mockMvc.perform(get("/")
.param("offset", "-1"))
.andExpect(status().isBadRequest());
}
@Test
public void getCarsInvalidLimit() throws Exception {
mockMvc.perform(get("/")
.param("limit", "0"))
.andExpect(status().isBadRequest());
mockMvc.perform(get("/")
.param("limit", "-1"))
.andExpect(status().isBadRequest());
mockMvc.perform(get("/")
.param("limit", "101"))
.andExpect(status().isBadRequest());
}
}
问题是使用无效参数的测试(上面代码片段中的两个测试)应该有 return 错误的请求,实际上 returning 200 OK 结果测试失败。
我该如何解决?
谢谢
我怀疑是因为您在模拟 MainController,所以 @Validated 没有生效。试试这个:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class TestMainController {
@Autowired
private MainController mainController;
@MockBean
private CarsService carsServiceMock;
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@Before
public void initMocks() {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.build();
}
独立设置无法做到这一点。
更多详情请参考:
对于@Validated 测试用例,我们需要:
MockMvcBuilders.webAppContextSetup()