spring-webmvc/hibernate-validator 在测试期间不会使坏数据失效

Posted

技术标签:

【中文标题】spring-webmvc/hibernate-validator 在测试期间不会使坏数据失效【英文标题】:spring-webmvc/hibernate-validator not invalidating bad data during test 【发布时间】:2021-09-30 12:51:14 【问题描述】:

我正在阅读 Spring In Action,并且正在研究 spring-mvc 的示例 spittr Web 应用程序。本书讨论了使用javax.annotation.constraints来描述有效数据,例如

import javax.validation.constraints.*;
public class Spitter 
   @NotNull
   @Size(min=5, max=16)
   private String username;
   //...

然后,它说,您可以将验证应用于使用 @Valid 装饰器作为参数的方法,例如

import        javax.validation.Valid;
import        org.springframework.stereotype.Controller;
import        org.springframework.validation.Errors;
import        org.springframework.web.bind.annotation.RequestMapping;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
@Controller
@RequestMapping("/spitter")
public class SpitterController 
  @RequestMapping(value="/register", method=POST)
  public String processRegistration(@Valid Spitter spitter, Errors errors) 
    if (errors.hasErrors()) 
      return "registerForm";
    
    return "redirect:/spitter/" + spitter.getUsername();
  
  //...

为了检查我对材料的理解,我尝试编写一些测试来查看该方法对无效数据的反应:

import        org.junit.Test;
import        org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultBuilders.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
public class SpitterControllerTest 
  @Test
  public void shouldNotProcessEmptyRegistration() throws Exception 
    standaloneSetup(new SpitterController())
      .build()
      .perform(post("/spitter/register"))
      .andExpect(view().name("registerForm"));
  
  @Test
  public void shouldNotProcessInvalidRegistration() throws Exception 
    standaloneSetup(new SpitterController())
      .build()
      .perform(post("/spitter/register").param("username", "x"))
      .andExpect(view().name("registerForm"));
  
  //...

当测试失败时我很惊讶

shouldNotProcessEmptyRegistration(spittr.web.SpitterControllerTest)  Time elapsed: 0.013 sec  <<< FAILURE!
java.lang.AssertionError: View name expected:<registerForm> but was:<redirect:/spitter/null>
shouldNotProcessInvalidRegistration(spittr.web.SpitterControllerTest)  Time elapsed: 0.013 sec  <<< FAILURE!
java.lang.AssertionError: View name expected:<registerForm> but was:<redirect:/spitter/x>

我不知道我做错了什么。我知道测试时发生的事情与类路径上的内容有很大关系:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.1.0.RELEASE</version>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.0.1</version>
</dependency>
<dependency>
  <groupId>org.hibernate.validator</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>6.1.13.Final</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>5.1.0.RELEASE</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.2</version>
  <scope>test</scope>
</dependency>

我认为我可能遗漏了本书没有提及的一些依赖关系,但在这一点上,我并不确定自己做错了什么。

我通过谷歌搜索找到的大部分内容都在讨论 spring-boot,我现在正试图推迟它;在我开始尝试了解 spring-boot 带来什么之前,我想先了解 spring(但 Spring Boot In Action 是我的阅读清单上的下一个)。

我需要做些什么来修复我的代码,以便控制器在测试时成功检测到无效数据?

【问题讨论】:

【参考方案1】:

似乎在您的代码中您要求 spitter 的用户名不能为空,但这并不意味着整个对象不能为空。在您当前的设置中,请求正文是可选的。你可以试试:

public String processRegistration(@RequestBody @Valid Spitter spitter, Errors errors)

默认情况下@RequestBody 要求正文。

【讨论】:

spitter 在此测试期间不是 null,如果是 spitter.getUsername() 将抛出 NullPointerException 而不是返回 null。我尝试按照您的指示添加 @RequestBody 装饰器,但这只是使测试失败,java.lang.AssertionError 即使给出了有效数据。 那我很糟糕,尽管我仍然看不到您的测试中的请求正文来自哪里。您提供的测试代码使它看起来像一个空的发布请求。 我将添加另一个测试以显示它对于非空但无效的用户名也失败

以上是关于spring-webmvc/hibernate-validator 在测试期间不会使坏数据失效的主要内容,如果未能解决你的问题,请参考以下文章