【问题标题】:Spring MockMvc Throwing Exception Rather than Expect in ResultSpring MockMvc 在结果中抛出异常而不是期望
【发布时间】:2022-01-03 17:00:38
【问题描述】:

我正在为控制器编写单元测试,这次我特意提出了一个会触发 ConstrainViolationException 的请求,在 mockmvc 中而不是期望它会引发错误。如何告诉spring不要扔它,让mvcresult验证结果

这是我的代码 sn-p

@WebMvcTest(ProductController.class)
public class ProductControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private ProductService productService;

    @BeforeEach
    public void setUp() throws Exception
    {
        this.mockMvc = MockMvcBuilders.standaloneSetup(new ProductController(productService))
                .setControllerAdvice(new ExceptionAdvice())
                .build();
    }

    @Test
    public void createProduct_With_InvalidRequest_ShouldReturn_BadRequest() throws Exception {

        ProductWebRequest productWebRequest = ProductWebRequest.builder()
                .sku(null)
                .productName(null)
                .barcode(null)
                .build();

        ProductServiceWebRequest productServiceWebRequest = ProductServiceWebRequest.builder()
                .sku(productWebRequest.getSku())
                .productName(productWebRequest.getProductName())
                .barcode(productWebRequest.getBarcode())
                .build();

        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        String json = ow.writeValueAsString(productWebRequest);

        BDDMockito.given(productService.createProduct(productServiceWebRequest)).willThrow(ConstraintViolationException.class);

        mockMvc.perform(MockMvcRequestBuilders.post("/v1/products")
                .contentType(MediaType.APPLICATION_JSON).content(json))
                .andExpect(MockMvcResultMatchers.status().isBadRequest())
                .andExpect(mvcResult -> Assertions.assertTrue(mvcResult.getResolvedException() instanceof ConstraintViolationException));
    }
}

ProductController.java

@RestController
@RequestMapping("/v1")
public class ProductController {

    private final ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @PostMapping(value = "/products", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public WebResponse createProduct(@RequestBody ProductWebRequest request)
    {
        ProductServiceWebRequest productServiceWebRequest = ProductServiceWebRequest.builder()
                .sku(request.getSku())
                .productName(request.getProductName())
                .barcode(request.getBarcode())
                .description(request.getDescription())
                .brand(request.getBrand())
                .material(request.getMaterial())
                .motif(request.getMotif())
                .colour(request.getColour())
                .price(request.getPrice())
                .weight(request.getWeight())
                .length(request.getLength())
                .width(request.getWidth())
                .height(request.getHeight())
                .category(request.getCategory())
                .hasVariant(request.getHasVariant())
                .build();

        ProductCreatedWebResponse productCreatedWebResponse = productService.createProduct(productServiceWebRequest);

        return WebResponse.builder()
                .statusCode(HttpStatus.OK.value())
                .statusName(HttpStatus.OK.name())
                .data(productCreatedWebResponse)
                .build();
    }

ExceptionAdvice.java

@Order(Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice
@Slf4j
public class ExceptionAdvice extends ResponseEntityExceptionHandler {

    @Override
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request)
    {
        List<String> errors = new ArrayList<>();

        for (FieldError error : ex.getBindingResult().getFieldErrors())
        {
            errors.add(error.getField() + " : " + error.getDefaultMessage());
        }
        for (ObjectError error : ex.getBindingResult().getGlobalErrors())
        {
            errors.add(error.getObjectName() +" : "+ error.getDefaultMessage());
        }

        WebResponse webResponse = WebResponse.builder()
                .error("API_ERROR")
                .errorDetail("REQUEST_NOT_CONFORM_PAYLOAD_STANDARD")
                .statusCode(HttpStatus.BAD_REQUEST.value())
                .statusName(HttpStatus.BAD_REQUEST.name())
                .build();

        log.error(errors.toString());

        return handleExceptionInternal(ex, webResponse, headers, HttpStatus.BAD_REQUEST, request);
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({ConstraintViolationException.class})
    public ResponseEntity<Object> handleConstraintViolation(ConstraintViolationException ex, WebRequest request)
    {
        List<String> errors = new ArrayList<String>();

        for (ConstraintViolation<?> violation : ex.getConstraintViolations())
        {
            errors.add(violation.getRootBeanClass().getSimpleName() + " - " + violation.getPropertyPath() + " : " + violation.getMessage().toUpperCase());
        }

        WebResponse webResponse = WebResponse.builder()
                .error("API_FAIL")
                .errorDetail("REQUEST_NOT_CONFORM_PAYLOAD_STANDARD")
                .statusCode(HttpStatus.BAD_REQUEST.value())
                .statusName(HttpStatus.BAD_REQUEST.name())
                .build();

        log.error(errors.toString());

        return new ResponseEntity<Object>(webResponse, new HttpHeaders(), HttpStatus.BAD_REQUEST);
    }
}

这是出现的错误

(ProductControllerTest.java:50)
Caused by: javax.validation.ConstraintViolationException

我知道这会引发异常,但是如何在期望部分中使用该异常进行断言?

【问题讨论】:

  • 可以在mvc中添加print方法来查看request的响应吗?
  • @huy 好吧,我看不到日志,即使我已经添加了一个 sout 来检查 mvc 结果,异常只是在 .expect 方法之前抛出
  • 你能帮忙添加完整的堆栈跟踪吗?让我们看看哪个类导致了 Constrain..Exception?

标签: java spring unit-testing


【解决方案1】:

ConstraintValidationException 有点特殊。

为了确保正确处理它,您可以这样做......

@Before
    public void setup() throws Exception {
        this.mockMvc = standaloneSetup(new MyController())
                .setControllerAdvice(new CustomExceptionHandler(), new ConstraintViolationsHandler())
                .build();
    }

这能解决您的问题吗?在 cmets 中告诉我。

【讨论】:

  • 我已经添加了一些代码,就像你说的那样@BeforeEachpublicvoidsetUp()throwsException{this.mockMvc=MockMvcBuilders.standaloneSetup(newProductController(productService)).setControllerAdvice(newExceptionAdvice()).build();} 我不知道你说的方法对吗?因为我仍然得到相同的结果Caused by: javax.validation.ConstraintViolationException
  • 好的,我先试试,稍后告诉你
  • 我已经检查了你给出的解决方案,但它似乎不像我所经历的那样,因为我能够给出如下所示的 400 响应response,但我是什么困惑的是为什么当mvc.perform方法expect永远不会执行时,它一直在抛出异常,我知道它会抛出异常,因为它符合预期
猜你喜欢
  • 2014-07-27
  • 2020-05-01
  • 2012-01-24
  • 2013-01-21
  • 1970-01-01
  • 2017-11-27
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多