Spring 始终启动@MockMvcTest MockHttpServletResponse returns 空体

Spring boot @MockMvcTest MockHttpServletResponse always returns empty body

我正在努力进行简单的 spring 启动休息控制器测试,它总是 return 空体响应。

这是我的测试代码:

@WebMvcTest(AdminRestController.class)
@AutoConfigureMockMvc(addFilters = false)
public class PatientsUnitTest {

    @Autowired
    private MockMvc mvc;

    @Autowired
    private ObjectMapper objectMapper;

    @MockBean
    private PatientsService patientsService;

    @MockBean
    private TherapistsService therapistsService;

    @MockBean
    private TherapySchedulesService therapySchedulesService;

    @Test
    public void canAddPatient() throws Exception {
        PatientsSaveRequestDto patientsSaveRequestDto = new PatientsSaveRequestDto();
        patientsSaveRequestDto.setName("Sofia");
        patientsSaveRequestDto.setPhone("01012345678");
        Patients patient = patientsSaveRequestDto.toEntity();

        when(patientsService.createPatient(patientsSaveRequestDto)).thenReturn(patient);

        final ResultActions actions = mvc.perform(post("/admin/patient")
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .characterEncoding(StandardCharsets.UTF_8.name())
                .content(objectMapper.writeValueAsString(patientsSaveRequestDto)))
                .andDo(print());

        actions
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
                .andExpect(jsonPath("name", is(patient.getName())))
                .andDo(print());
    }

我的控制器:

@RestController
@RequiredArgsConstructor
public class AdminRestController {
    private final PatientsService patientsService;
    private final TherapistsService therapistsService;
    private final TherapySchedulesService therapySchedulesService;

    @PostMapping("/admin/patient")
    @ResponseStatus(HttpStatus.OK)
    @Operation(summary = "Create a patient")
    public Patients cratePatient(
            @RequestBody @Valid PatientsSaveRequestDto patientsSaveRequestDto
    ) {
        return patientsService.createPatient(patientsSaveRequestDto);
    }

// PatientsService
@Transactional
    public Patients createPatient(PatientsSaveRequestDto patientsSaveRequestDto){
        return patientsRepository.save(patientsSaveRequestDto.toEntity());
    }

这是 print() 的结果:

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /admin/patient
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"53"]
             Body = {"name":"sofia","phone":"01012345678","tel":null}
    Session Attrs = {}

Handler:
             Type = com.ussoft.dosu.web.controller.admin.AdminRestController
           Method = com.ussoft.dosu.web.controller.admin.AdminRestController#cratePatient(PatientsSaveRequestDto)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

如您所见,请求已正确发送,但响应值为空。

当我使用@SpringBootTest 和 Rest Assured 测试同一个控制器时,它工作正常。

我正在使用 Spring boot 2.3.1,Junit5


编辑 - 添加 PatientsSaveRequestDto

@Getter
@Setter
@NoArgsConstructor
public class PatientsSaveRequestDto {
    @NotBlank(message = "이름은 필수 입력사항입니다.")
    private String name;

    private String phone;

    private String tel;

    public Patients toEntity(){
        return Patients.builder()
                .name(name)
                .phone(phone)
                .tel(tel)
                .build();
    }
}

您需要为 PatientsSaveRequestDto 提供 equals 方法。

当您在 mock 上执行方法时,Mockito 需要检查是否为调用该方法的参数指定了任何行为。

  • 如果参数匹配,记录结果为returned,
  • 如果参数不匹配,方法 return 类型的默认值是 returned(所有对象为 null,数字为零,bool 为 false)

您通过以下调用记录了该行为:

when(patientsService.createPatient(patientsSaveRequestDto)).thenReturn(patient);

这意味着 createPatient 的实际参数将与 patientsSaveRequestDtoequals 进行比较。

请注意,可以通过使用 ArgumentMatchers 来更改此行为。

测试中的 patientsSaveRequestDtocreatePatient 的实际参数不相等,因为:

  • 你没有定义 equals 方法
  • 它们是不同的实例
  • 因此,继承的Object.equals returns false

您有 2 个不同的实例,因为您创建了 @WebMvcTest。 您发送到控制器的 patientsSaveRequestDto 首先序列化为 String,然后反序列化,这就是创建第二个实例的方式。