【问题标题】:Spring Boot - Test - Validator: Invalid target for ValidatorSpring Boot - 测试 - 验证器:验证器的目标无效
【发布时间】:2017-07-25 10:01:37
【问题描述】:

我在尝试运行测试时收到以下错误:

org.springframework.web.util.NestedServletException:请求处理失败;嵌套异常是 java.lang.IllegalStateException: Invalid target for Validator [userCreateFormValidator bean]: com.ar.empresa.forms.UserCreateForm@15c3585

原因:java.lang.IllegalStateException:Validator [userCreateFormValidator bean] 的目标无效:com.ar.empresa.forms.UserCreateForm@15c3585 在 org.springframework.validation.DataBinder.assertValidators(DataBinder.java:567) 在 org.springframework.validation.DataBinder.addValidators(DataBinder.java:578) 在 com.ar.empresa.controllers.UserController.initBinder(UserController.java:36) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498)

代码是:

控制器:

@Controller
public class UserController {
private UserService userService;
private UserCreateFormValidator userCreateFormValidator;

@Autowired
public UserController(UserService userService, UserCreateFormValidator userCreateFormValidator) {
    this.userService = userService;
    this.userCreateFormValidator = userCreateFormValidator;
}

@InitBinder("form")
public void initBinder(WebDataBinder binder) {
    binder.addValidators(userCreateFormValidator);
}

@PreAuthorize("hasAuthority('ADMIN')")
@RequestMapping(value = "/user/create", method = RequestMethod.GET)
public ModelAndView getUserCreatePage() {
    return new ModelAndView("user_create", "form", new UserCreateForm());
}

@PreAuthorize("hasAuthority('ADMIN')")
@RequestMapping(value = "/user/create", method = RequestMethod.POST)
public String handleUserCreateForm(@Valid @ModelAttribute("form") UserCreateForm form, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "user_create";
    }
    try {
        userService.create(form);
    } catch (DataIntegrityViolationException e) {
        bindingResult.reject("email.exists", "Email already exists");
        return "user_create";
    }
    return "redirect:/users";
}
}

验证器:

@Component
public class UserCreateFormValidator implements Validator {

private final UserService userService;

@Autowired
public UserCreateFormValidator(UserService userService) {
    this.userService = userService;
}

@Override
public boolean supports(Class<?> clazz) {
    return clazz.equals(UserCreateForm.class);
}

@Override
public void validate(Object target, Errors errors) {
    UserCreateForm form = (UserCreateForm) target;
    validatePasswords(errors, form);
    validateEmail(errors, form);
}

private void validatePasswords(Errors errors, UserCreateForm form) {
    if (!form.getPassword().equals(form.getPasswordRepeated())) {
        errors.reject("password.no_match", "Passwords do not match");
    }
}

private void validateEmail(Errors errors, UserCreateForm form) {
    if (userService.getUserByEmail(form.getEmail()).isPresent()) {
        errors.reject("email.exists", "User with this email already exists");
    }
}
}

用户创建表单:

public class UserCreateForm {

@NotEmpty
private String email = "";

@NotEmpty
private String password = "";

@NotEmpty
private String passwordRepeated = "";

@NotNull
private Role role = Role.USER;

public String getEmail() {
    return email;
}

public String getPassword() {
    return password;
}

public String getPasswordRepeated() {
    return passwordRepeated;
}

public Role getRole() {
    return role;
}

public void setEmail(String email) {
    this.email = email;
}

public void setPassword(String password) {
    this.password = password;
}

public void setPasswordRepeated(String passwordRepeated) {
    this.passwordRepeated = passwordRepeated;
}

public void setRole(Role role) {
    this.role = role;
}
}

测试:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest {

private MockMvc mockMvc;

private MediaType contentType = new MediaType(APPLICATION_JSON.getType(),
        APPLICATION_JSON.getSubtype(),
        Charset.forName("utf8"));

@MockBean
private UserService userService;

@MockBean
private UserCreateFormValidator userCreateFormValidator;

@Autowired
FilterChainProxy springSecurityFilterChain;

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders.standaloneSetup(new UserController(userService,userCreateFormValidator)).apply(SecurityMockMvcConfigurers.springSecurity(springSecurityFilterChain)).build();
}

@Test
@WithMockUser(username="user",
        password="password",
        roles="ADMIN")
public void homePage_authenticatedUser() throws Exception {
    mockMvc.perform(get("/user/create"))
            .andExpect(status().isOk())
            .andExpect(view().name("user_create"));
}
}

我不知道为什么,因为它是一个GET方法,所以它不必验证它。 谢谢! :)

【问题讨论】:

    标签: spring spring-mvc spring-boot spring-test spring-test-mvc


    【解决方案1】:

    你得到这个异常是因为你没有在你的 userCreateFormValidator @Mockbean 上模拟 public boolean supports(Class&lt;?&gt; clazz) 方法的行为。 如果您从您发布的日志中查看org.springframework.validation.DataBinder.assertValidators(DataBinder.java) 的代码,您可以在那里找到如何处理验证器以及如何抛出java.lang.IllegalStateException。在Spring 4.3.8,是这样的

    if(validator != null && this.getTarget() != null && !validator.supports(this.getTarget().getClass())) {
        throw new IllegalStateException("Invalid target for Validator [" + validator + "]: " + this.getTarget());
    }
    

    你没有模拟验证器的supports方法,默认返回false,导致上面的Spring代码抛出IllegalStateException

    TLDR,给我解决方案:

    你必须在你的验证器上模拟 supports 方法。在@Before@BeforeClass 方法中添加以下内容。

    when(requestValidatorMock.supports(any())).thenReturn(true);
    

    【讨论】:

      【解决方案2】:

      我无法评论正确答案,但他的解决方案有效:

      这是我必须为这个确切的错误做的事情。

      //Imports
      import static org.mockito.ArgumentMatchers.any;
      import static org.mockito.Mockito.when;
      
      
          @MockBean
          ApiValidationRouter apiValidationRouter;
      
          @Before
          public void beforeClass() throws Exception {
              when(apiValidationRouter.supports(any())).thenReturn(true);
          }
      
      

      【讨论】:

        猜你喜欢
        • 2021-03-18
        • 1970-01-01
        • 1970-01-01
        • 2020-07-25
        • 1970-01-01
        • 1970-01-01
        • 2018-04-27
        • 2017-04-14
        • 1970-01-01
        相关资源
        最近更新 更多