SpringWebMvcTest - 使用 @Valid 和自定义验证测试 Requestbody

Posted

技术标签:

【中文标题】SpringWebMvcTest - 使用 @Valid 和自定义验证测试 Requestbody【英文标题】:SpringWebMvcTest - Test Requestbody using @Valid and custom validation 【发布时间】:2018-03-14 17:31:21 【问题描述】:

我正在尝试测试我的控制器端点和带有@Valid 注释的请求正文。我的 Testclass 如下所示:

@RunWith(SpringRunner.class)
@WebMvcTest(value = BalanceInquiryController.class, secure = false)
public class BalanceInquiryControllerTest 

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private BalanceInquiryController balanceInquiryController;

    @Test
    public void testGetBalanceInquiry() throws Exception 
        RequestBuilder requestBuilder = MockMvcRequestBuilders
                .post("/com/balanceInquiry")
                .accept(MediaType.APPLICATION_JSON)
                .content("\"comGiftCard\":\"cardNumber\":\"1234567890\",\"pinNumber\":\"0123\",\"comMerchant\":\"MERCHANT1\"")
                .contentType(MediaType.APPLICATION_JSON);

        MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn();
        MockHttpServletResponse response = mvcResult.getResponse();
        assertEquals(HttpStatus.OK.value(), response.getStatus());
    

我的控制器 - @PostMapping 看起来像这样:

@PostMapping(value = "/com/balanceInquiry")
public ResponseEntity<?> getBalanceInquiry(@Valid @RequestBody BalanceInquiryModel balanceInquiry, Errors errors) 
    if (errors.hasErrors()) 
        return new ResponseEntity<String>("Validation error", HttpStatus.BAD_REQUEST);
    
    //do any stuff...
    return new ResponseEntity<BalanceInquiryResponse>(balanceInquiryResponse, HttpStatus.OK);

我的BalanceInquiryModel 带有@Valid 注释,并且有一些休眠和自定义验证。这些验证都可以,并且已经过单元测试。

我想测试的是我的端点,我发送一个有效的 json 请求正文,期望得到 200 响应,以及一个无效的 json 请求正文,期望得到 400 响应,由 set @Valid 实现验证。

例如,一个无效的调用是不发送 pinNumber 或长度

我已经阅读了一些线程和一些使用MockMvcBuilders.standaloneSetup() 来模拟完整的控制器。但我不会做一个完整的集成测试。

不太确定如何处理这种情况以及是否应该继续。

P.S.:目前,无论验证是否应该给出错误,我总是得到 200 响应。

Here a gist 获取更多代码和验证类/模型。

【问题讨论】:

你在邮递员中测试过,验证失败时会得到 400? @ChiDov 是的。例如,当我发送 pinNumber 长度 【参考方案1】:

这是我在项目中工作的一个示例 希望对你有所帮助:

我有一个全局异常处理程序来处理我的 MethodArgumentNotValidException 并抛出它

@RequestMapping(value = "/add", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<User> createUser(@Valid @RequestBody User user) 

        User savedUser = userService.save(user);

        return new ResponseEntity<User>(savedUser, HttpStatus.CREATED);
    


public void testAdduser() throws Exception
        final User request = new User();
        request.setFirstName("Test");
        request.setLastName("some description");

        mockMvc.perform(post(END_POINT+"/add")
                .contentType(MediaType.APPLICATION_JSON)
                .content(stringify(request))

        ).andDo(print()).andExpect(status().isUnprocessableEntity())
        ;
    
private String stringify(Object object) throws JsonProcessingException 
        return new ObjectMapper().writeValueAsString(object);
    

更新:

我认为您的主要问题是您使用 @WebMvcTest 而不是 @SpringBootTest

两者的区别在于:

@SpringBootTest 注释将加载完整的应用程序并注入所有可能很慢的 bean。

@WebMvcTest - 用于测试控制器层。它不会在 @RestController 旁边注入其他 bean

因此,如果您只是测试纯控制器以查看您是否可以到达端点,那么您可以使用 @WebMvcTest 这将使您的测试运行得更快。

但在您的情况下,您希望它运行 spring 验证,您需要使用 @SpringBootTest

详情:https://spring.io/guides/gs/testing-web/

【讨论】:

如果您不发送名字,您的验证是否可以? 不行,实际上用户对象有其他验证,即使我发送名字姓氏它仍然不期望200返回 你能和我分享你的 git repo 吗?我很高兴看到这个

以上是关于SpringWebMvcTest - 使用 @Valid 和自定义验证测试 Requestbody的主要内容,如果未能解决你的问题,请参考以下文章

va_start和va_end的使用及原理

[C]va_list可变长参数的使用

带有帖子的 Spring WebMvcTest 返回 403

使用 va_copy 有啥意义?

使用的类型 va_list (aka_builtin_va_list) 在 BWDB.m 文件中需要算术或指针类型

不确定函数参数个数时的处理,va_start和va_end使用详解