【问题标题】:How to check values in response body with mockMvc - AssertionError: Status expected:<201> but was:<400>如何使用 mockMvc 检查响应正文中的值 - AssertionError: Status expected:<201> but was:<400>
【发布时间】:2020-09-13 06:02:50
【问题描述】:

我是测试写作新手,我正在尝试使用 mockMvc 为我的控制器类编写 junit 测试。

这是我的课程:

public class StudentDTO {

private final String firstName;
private final String lastName;
private final String JMBAG;
private final Integer numberOfECTS;
private final boolean tuitionShouldBePaid;}

命令类

public class StudentCommand { 
@NotBlank (message = "First name must not be empty!")
private String firstName;

@NotBlank (message = "Last name must not be empty!")
private String lastName;


@NotNull(message = "Date of birth must be entered!")
@Past(message = "Date of birth must be in the past!")
private LocalDate dateOfBirth;

@NotBlank(message = "JMBAG must not be empty!")
@Pattern(message = "JMBAG must have 10 digits", regexp = "[\\d]{10}")
private String jmbag;

@NotNull(message = "Number of ECTS points must be entered!")
@PositiveOrZero(message = "Number of ECTS points must be entered as a positive integer!")
private Integer numberOfECTS;}

控制器类:

@Secured({"ROLE_ADMIN"})
@PostMapping
public ResponseEntity<StudentDTO> save(@Valid @RequestBody final StudentCommand command){
    return studentService.save(command)
            .map(
                    studentDTO -> ResponseEntity
                            .status(HttpStatus.CREATED)
                            .body(studentDTO)
            )
            .orElseGet(
                    () -> ResponseEntity
                            .status(HttpStatus.CONFLICT)
                            .build()
            );
}

测试类:

@SpringBootTest
@AutoConfigureMockMvc class StudentControllerTest {
@Autowired
private MockMvc mockMvc;

@MockBean
private StudentService studentServiceMock;

@Autowired
private ObjectMapper objectMapper;

private final String TEST_FIRST_NAME = "Marry";
private final String TEST_LAST_NAME = "Blinks";
private final String TEST_JMBAG = "0025478451";
private final Integer TEST_NUMBER_OF_ECTS = 55;
private final boolean TEST_TUITION_SHOULD_BE_PAID = true;
private final LocalDate TEST_DATE_OF_BIRTH = LocalDate.parse("1999-01-12");

@Test
void testSave() throws Exception {

    StudentCommand studentCommand = new StudentCommand(TEST_FIRST_NAME,TEST_LAST_NAME,TEST_DATE_OF_BIRTH,TEST_JMBAG,TEST_NUMBER_OF_ECTS);

    this.mockMvc.perform(
            post("/student")
                    .with(user("admin")
                            .password("test")
                            .roles("ADMIN")
                    )
                    .with(csrf())
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(studentCommand))
            .accept(MediaType.APPLICATION_JSON)
    )
            .andExpect(status().isCreated())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
            .andExpect(jsonPath("$.jmbag").value(TEST_JMBAG))
            .andExpect(jsonPath("$.firstName").value(TEST_FIRST_NAME))
            .andExpect(jsonPath("$.lastName").value(TEST_LAST_NAME));
}

我总是因为这个错误而导致测试失败:


MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /student
       Parameters = {_csrf=[30de7a8f-a3d5-429d-a778-beabd1a533da]}
          Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json", Content-Length:"272"]
             Body = {"firstName":"Marry","lastName":"Blinks","dateOfBirth":{"year":1999,"month":"JANUARY","monthValue":1,"dayOfMonth":12,"chronology":{"id":"ISO","calendarType":"iso8601"},"dayOfWeek":"TUESDAY","leapYear":false,"dayOfYear":12,"era":"CE"},"jmbag":"0025478451","numberOfECTS":55}
    Session Attrs = {}
Handler:
             Type = com.studapp.students.StudentController
           Method = com.studapp.students.StudentController#save(StudentCommand)
MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
java.lang.AssertionError: Status expected:<201> but was:<400>
Expected :201
Actual   :400

我不确定它为什么会失败。为什么响应正文为空白?我不想调用我的服务,因为我没有测试它,但我觉得我应该以某种方式调用它(但话又说回来,我没有测试服务)。 任何建议将不胜感激。

【问题讨论】:

  • 我需要以某种方式模拟服务以便 mockMvc 可以从中获取元素吗?
  • 你能展示一下Test类的顶部吗?您在其上使用了哪些注释以及如何自动连接 mockMvc 和 objectMapper?
  • @Sebastian @SpringBootTest @AutoConfigureMockMvc class StudentControllerTest { @Autowired private MockMvc mockMvc; private ObjectMapper objectMapper = new ObjectMapper(); 所以我的 objectMapper 没有注释,我不知道它需要什么
  • 所以即使我现在用 @Autowire 注释 objecMapper 它也会显示错误状态预期: 但原为:
  • 你能否展示你是如何构建你传递给这个new StudentCommand(TEST_FIRST_NAME,TEST_LAST_NAME,TEST_DATE_OF_BIRTH,TEST_JMBAG,TEST_NUMBER_OF_ECTS); 的每个值的

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


【解决方案1】:

您应该在 ObjectMapper 上使用 @Autowired 以确保 Spring 以与应用程序运行时相同的方式对其进行配置。这可以解释您收到的 400 - Bad request 错误。

自动装配ObjectMapper 后发生 409 - Conflict 的事实表明这确实是错误。 由于您没有在测试中配置 studentServiceMock,因此 409 似乎是控制器的合适答案,因为正在执行 orElseGet 部分。

如果我没记错的话,你可以稍微精简一下测试类注释,只使用@WebMvcTest。这对于这种测试应该足够了,而且应该会快一点。

【讨论】:

  • 保存对象时如何测试它?
  • 行为驱动,它看起来像这样:given(studentServiceMock.save(any(StudentCommand.class).willReturn(studentCommand); 这应该添加到测试中的StudentCommand studentCommand = new StudentCommand...... 行下方。但我没有对此进行测试。
  • 哦,看起来你的save 返回了一个 Optional。在这种情况下,它看起来像这样:given(studentServiceMock.save(any(StudentCommand.class).willReturn(Optional.of(studentCommand));
  • 我得到了模棱两可的方法调用。 matchers 中的 any(Class) 和 ArgumentMatchers 中的 any(Class) 都匹配。
  • 它们应该在org.mockito.ArgumentMatchers 类中。您可以简单地添加静态导入:import static org.mockito.ArgumentMatchers.any; given 来自 org.mockito.BDDMockito 类。
猜你喜欢
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-02
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多