我正在尝试测试验证,我有一个控制器
@RestController
@RequestMapping("/product")
@RequiredArgsConstructor
@CrossOrigin
public class ProductController {
private final ProductService productService;
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping
public ProductResponse createProduct(@RequestBody @Valid ProductRequest request) {
return productService.createProduct(request);
}
}
服务
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductServiceImpl implements ProductService {
private final ProductMapper productMapper;
private final ProductRepository productRepository;
@Override
@Transactional
public ProductResponse createProduct(ProductRequest productRequest) {
Product product = productMapper.mapToEntity(productRequest);
Product savedProduct = productRepository.save(product);
log.info("New product saved. Id = {}", savedProduct.getId());
return productMapper.mapToResponse(savedProduct);
}
}
带有控制器和服务的Spring验证注解的DTO
@Getter
@Setter
public class ProductRequest {
@NotBlank(message = "{name.not-blank}")
private String name;
@Positive(message = "{amount.positive}")
private Integer amount;
@Positive(message = "{price.positive}")
private Double price;
}
www.example.com文件中的消息message.properties:
name.not-blank=Name field is required
在RestExceptionHandler中处理异常:
@ExceptionHandler(MethodArgumentNotValidException.class)
protected ResponseEntity<ExceptionResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
String message = ex.getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.joining(", "));
ExceptionResponse response = new ExceptionResponse(message);
log.error(message);
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
如果我启动应用程序,但没有填写ProductRequest的name字段,则会根据我的www.example.com文件收到消息messages.properties:“Name field is required”enter image description here
但是,如果我创建测试,并且在创建ProductRequest时没有填充相同的字段:
public class ProductServiceTest {
private final ProductRepository productRepository = mock(ProductRepository.class);
private final ProductMapper productMapper = new ProductMapperImpl();
private final ProductServiceImpl productService =
new ProductServiceImpl(
productMapper,
productRepository);
@Test
void whenEmptyNameProduct() {
var productRequest = buildProduct();
var product = productMapper.mapToEntity(productRequest);
when(productRepository.save(any())).thenReturn(product);
var productResponse = productMapper.mapToResponse(product);
MethodArgumentNotValidException thrown = assertThrows(
MethodArgumentNotValidException.class,
() -> productService.createProduct(productRequest));
assertTrue(thrown.getMessage().contentEquals("Name field is required"));
}
private ProductRequest buildProduct() {
ProductRequest request = new ProductRequest();
// request.setName("");
request.setAmount(0);
request.setPrice(500.0);
return request;
}
}
我从控制台收到消息:
org.opentest4j.AssertionFailedError:应引发org.springframework.web.bind.MethodArgumentNotValidException异常,但未引发任何异常。
enter image description here
我也尝试过从RestExceptionHandler中删除异常处理,然后启动应用程序,但在这种情况下,我得到了这样的消息:
已解决[org.springframework.web.bind.方法参数无效异常:验证公共com.guavapay.delivery.dto.response.ProductResponse com.guavapay.delivery.controller.ProductController.createProduct(com.guavapay.delivery.dto.request.ProductRequest)中的参数[0]失败:[对象'productRequest'中字段'name'上的字段错误:拒绝值[];代码[NotBlank.productRequest.name,NotBlank.name,非空白.java.lang.字符串,非空白];参数[org.springframework.context.support.默认消息源可解析:代码[productRequest.name,名称];参数[];默认消息[名称]];默认消息[名称字段为必填字段]] ]
enter image description here,其中包含方法参数无效异常。
我很困惑,我需要做什么来正确测试@NotBlank注解并获得MethodArgumentNotValidException以便在测试中Assert?
你能给我点建议吗?
1条答案
按热度按时间sdnqo3pr1#
看起来您好像绕过了
Spring
注入,所以我不希望像RestExceptionHandler
这样的东西被调用。我不知道您使用的是什么样的mock框架,但这是
SpringBoot
Mockito
版本的样子。