Mockito和JUnit控制器测试返回400对任何请求体json



我有一个映射到补丁数据:

@Data
@NoArgsConstructor
public class CertificateUpdateDTO {
@InjectString
private String name;
@InjectString
private String description;
@Min(value = 0, message = "Price cannot be negative")
private double price;
@Min(value = 1, message = "Duration cannot be less than one day")
private int duration;
}

@ApiOperation("Update certificate by id")
@ApiResponses({
@ApiResponse(code = 200, message = "If updated successfully or certificate doesn't exist"),
@ApiResponse(code = 400, message = "If JSON object in request body is invalid"),
@ApiResponse(code = 404, message = "Certificate with given id doesn't exist")
})
@PatchMapping(value = "/{id}", consumes = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity update(@PathVariable int id, @Valid @DefaultDto CertificateUpdateDTO certificateUpdateDTO){
if(certificateService.updateCertificate(id, certificateUpdateDTO)){
return ResponseEntity.ok().build();
}
return ResponseEntity.notFound().build();
}

@DefaultDto@InjectString是我的注释,他们只是做相同的@RequestBody和注入默认值到@InjectString注释的字符串字段,它工作得很好。

我需要检查对id为1的映射的请求是否返回404,并且它可以从curl工作:

curl -X PATCH -H "Content-Type: application/json" -d '{"duration": "10", "price": "10"}' localhost:8080/v1/certificate/1

curl的响应码为404。但是当我尝试运行测试时,它返回400:

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ControllerTestConfiguration.class, loader = AnnotationConfigContextLoader.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class CertificateControllerTest {
@Autowired
private CertificateService certificateService;
@Autowired
private CertificateController certificateController;
private ObjectMapper objectMapper = new ObjectMapper();
private MockMvc mockMvc;
@BeforeAll
public void init(){
mockMvc = MockMvcBuilders.standaloneSetup(certificateController).build();
}
@AfterEach
public void postEach(){
reset(certificateService);
}
...    
@Test
@SneakyThrows
public void updateFailTest(){
CertificateUpdateDTO certificateUpdateDTO = new CertificateUpdateDTO();
certificateUpdateDTO.setName("c1");
certificateUpdateDTO.setDescription("desk");
certificateUpdateDTO.setDuration(10);
certificateUpdateDTO.setPrice(10);
when(certificateService.updateCertificate(1, certificateUpdateDTO)).thenReturn(false);
mockMvc.perform(patch("/v1/certificate/1")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(certificateUpdateDTO))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is(404));
verify(certificateService, times(1)).updateCertificate(1, certificateUpdateDTO);
}
}

当前测试类的配置为:

@Configuration
public class ControllerTestConfiguration {
...
@Bean
public CertificateService certificateService(){
return mock(CertificateService.class);
}
@Bean
public CertificateController certificateController(){
return new CertificateController(certificateService());
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}

持续时间无效:duration = 0

乌利希期刊指南:

我想删除@Valid,看到我的注释不工作在测试环境,我如何处理:

public class DefaultValueHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterAnnotation(DefaultDto.class) != null;
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
HttpServletRequest servletRequest = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
BufferedReader reader = servletRequest.getReader();
String body = reader.lines().collect(Collectors.joining());
Class<?> clazz = methodParameter.getParameterType();
Object dto = new ObjectMapper().readValue(body, clazz);
for(Field field : clazz.getDeclaredFields()){
InjectString annotation = field.getAnnotation(InjectString.class);
if(annotation != null){
field.setAccessible(true);
if(ReflectionUtils.getField(field, dto) == null) {
ReflectionUtils.setField(field, dto, annotation.value());
}
}
}
return dto;
}
}

我就是这样注册MethodResolver的:

public class AppConfig implements WebMvcConfigurer {
private final Environment env;
@Autowired
public AppConfig(Environment env) {
this.env = env;
}
...
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new DefaultValueHandlerMethodArgumentResolver());
}

...
}

经过一些研究和我的leed朋友的帮助,我找到了解决方案:)

要添加自定义的ArgumentResolver,你应该在MockMvcBuilder中注册它。

改变:

mockMvc = MockMvcBuilders.standaloneSetup(certificateController).build();

:

mockMvc = MockMvcBuilders.standaloneSetup(certificateController).setCustomArgumentResolvers(new DefaultValueHandlerMethodArgumentResolver()).build();

最新更新