首页 > 解决方案 > Spring Boot Validation:如何测试 DTO 对象

问题描述

我有StudentController我必须测试的方法。我想测试StudentDTO验证:

@PostMapping("successStudentAddition")
public String addStudent(@ModelAttribute("student") @Validated StudentDTO studentDTO, Errors errors, Model model) {

    if (errors.hasErrors()) {
        model.addAttribute(STUDENT_MODEL, studentDTO);
        return "/studentViews/addStudent";
    }

    Student student = new Student(studentDTO.getStudentId(), studentDTO.getStudentName(), studentDTO.getStudentSurname(),
            studentDTO.getStudentAge(), studentDTO.getEntryYear(), studentDTO.getGraduateYear(), studentDTO.getFacultyName(),
            groupService.getGroupIdByName(studentDTO.getGroupName()));
    studentService.addStudent(student);
    return "/studentViews/successStudentAddition";
}

StudentDTO.class

public class StudentDTO {
@Id
private int studentId;
@NotNull
@Size(min=2,max=30,message = "Name should consist of 2 to 30 symbols!")
private String studentName;
@NotNull
@Size(min = 2, max = 30,message = "Surname should consist of 2 to 30 symbols!")
private String studentSurname;
@NotNull
@Min(value = 10,message = "Student age should be more than 10!")
private int studentAge;
@NotNull
@Min(value = 1900,message = "Entry year should be more than 1900!")
@Max(value=2021,message = "Entry year should be less than 2021!")
private int entryYear;
@NotNull
@Min(value = 2020,message = "Graduate year should be not less than 2020!")
private int graduateYear;
@NotNull
@Size(min = 3,message = "Faculty name should consist of minimum 3 symbols!")
private String facultyName;
@NotNull
@Size(min = 4,message = "Group name should consist of 4 symbols!")
@Size(max = 4)
private String groupName;
}

我找到了一些测试的想法:

@ExtendWith(SpringExtension.class)
@SpringBootTest
class ValidatingServiceWithGroupsTest {
  @Autowired
private ValidatingServiceWithGroups service;
@Test
void whenInputIsInvalidForCreate_thenThrowsException() {
InputWithGroups input = validInput();
input.setId(42L);

assertThrows(ConstraintViolationException.class, () -> {
  service.validateForCreate(input);
});
}
@Test
void whenInputIsInvalidForUpdate_thenThrowsException() {
InputWithGroups input = validInput();
input.setId(null);

assertThrows(ConstraintViolationException.class, () -> {
  service.validateForUpdate(input);
});
}
}

但。如果在上面的代码中我们在没有任何输入参数的情况下测试服务,我应该使用这样的参数给控制器:Errors errorsModel model。我有麻烦。

添加 test 后的所有堆栈跟踪:

java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'studentController': Unsatisfied dependency expressed through field 'studentService'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.foxminded.springboot.service.StudentService' available: expected at least 1 bean which qualifies as autowire 
candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.foxminded.springboot.service.StudentService' available: expected at least 1 bean which qualifies as 
autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

标签: spring-bootvalidationjunit

解决方案


根据您在问题中提供的内容,我了解您需要测试StudentDTO dto 类的验证。dto 类的验证将在 spring 自动绑定时触发。因此,要测试此验证,您只需使用将触发验证并检查响应的 json 正确调用控制器方法。如果验证失败,它将触发MethodArgumentNotValidException. 默认情况下,Spring 会将此异常转换为 HTTP 状态 400(错误请求)。

@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = StudentController.class)
class StudentControllerTest {

  @Autowired
  private MockMvc mvc;

  @Autowired
  private ObjectMapper objectMapper;

  @MockBean
  private StudentService service;

  @Test
  void whenInputIsInvalid_thenReturnsStatus400() throws Exception {
    Input input = invalidInput();
    String body = objectMapper.writeValueAsString(input);

    mvc.perform(post("/successStudentAddition")
            .content(body))
            .andExpect(status().isBadRequest());
  }
}

但是在您的情况下,发生错误时您将返回不同的视图,因此您需要对此进行测试。因此,在您的情况下测试响应,例如:

this.mockMvc.perform(post("/successStudentAddition")
.accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(model().attribute("yourmodel", "assertIt"))
.andDo(print());

推荐阅读