【问题标题】:How to test InternalServerError using mockito in Repository?如何在存储库中使用 mockito 测试 InternalServerError?
【发布时间】:2021-10-21 03:04:50
【问题描述】:

我正在编写一个测试来测试控制器中失败情况的 POST 方法。 它返回 415,我期待 500。我使用 mockito 模拟了响应。 控制器测试

@Test
@DisplayName("POST /customers - Failure")
void createProductShouldFail() throws Exception {
    // Setup mocked service
    when(customerService.save(any(Customer.class))).thenThrow(HttpServerErrorException.InternalServerError.class);
    RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/customers").accept(MediaType.APPLICATION_JSON)
            .content("{\"name\":\"John\"}");
    MvcResult result=mockMvc.perform(requestBuilder).andReturn();
    MockHttpServletResponse response = result.getResponse();
            // Validate the response code and content type
    assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), response.getStatus());
}

控制器

    @PostMapping(path = "/customers")
public ResponseEntity<Customer> saveCustomer(@RequestBody Customer customer){
    try {
        // Create the new product
        Customer savedCustomer = customerService.save(customer);
        // Build a created response
        return ResponseEntity
                .created(new URI("/customers/" + savedCustomer.getId()))
                .body(savedCustomer);
    } catch (URISyntaxException e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

错误:

      HTTP Method = POST
      Request URI = /customers
       Parameters = {}
          Headers = [Accept:"application/json", Content-Length:"15"]
             Body = {"name":"John"}
    Session Attrs = {}

Handler:
             Type = com.prabhakar.customer.controller.CustomerController
           Method = com.prabhakar.customer.controller.CustomerController#saveCustomer(Customer)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = org.springframework.web.HttpMediaTypeNotSupportedException

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

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 415
    Error message = null
          Headers = [Accept:"application/json, application/*+json"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

org.opentest4j.AssertionFailedError: 
Expected :500
Actual   :415

但是 415-Unsupported Media Type 客户端错误响应代码。

我为这个方法使用了相同的有效负载,它有效。

  

      @Test
        @DisplayName("POST /customers - Success")
        void createProductShouldSucceed() throws Exception {
            // Setup mocked service
            Customer mockCustomer = new Customer(1L, "John");
            when(customerService.save(any(Customer.class))).thenReturn(mockCustomer);
            this.mockMvc.perform(post("/customers")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content("{\"name\":\"John\"}"))
                    // Validate the response code and content type
                    .andExpect(status().isCreated())
                    .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                    //Validate returned json fields
                    .andExpect(jsonPath("$.id").value(1L))
                    .andExpect(jsonPath("$.name").value("John"));
        }

Update I have added
@RestController
@EnableWebMvc

这会引发一个模拟错误但代码在mockmvc.perform附近中断。

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.HttpServerErrorException$InternalServerError

如何验证这是否有效。 assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), response.getStatus());

【问题讨论】:

    标签: java spring-boot mockito spring-boot-test


    【解决方案1】:

    可以参考Spring MVC Test Framework - Unsupported Media Type

    您的控制器中可能缺少 @EnableWebMvc 注释。

    编辑 - 评论:

    而不是

    RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/customers").accept(MediaType.APPLICATION_JSON)
            .content("{\"name\":\"John\"}");
    MockHttpServletResponse response = result.getResponse();
            // Validate the response code and content type
    assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), 
    response.getStatus());
        
    

    试试:

      mockMvc.perform(requestBuilder)
                .andExpect(status().isInternalServerError());
    

    【讨论】:

    • 我已将@EnableWebMvc 添加到控制器。 Request processing failed; nested exception is org.springframework.web.client.HttpServerErrorException$InternalServerError .
    • 是的,我试过了。它似乎有同样的错误。
    • 你能分享堆栈跟踪看看这个 InternalServerError 来自哪里。
    • at com.prabhakar.customer.controller.CustomerControllerTest.createProductShouldFail(CustomerControllerTest.java:61) 并指向mvc.**perform**
    • 可以参考:baeldung.com/spring-mvc-test-exceptionsmvc.perform(get("/exception/{exception_id}", exceptionParam) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isInternalServerError() )
    【解决方案2】:

    要解决问题,您必须考虑两件事:

    • 首先,您必须使用.contentType(MediaType.APPLICATION_JSON),而不是使用.accept(MediaType.APPLICATION_JSON)

    • 第二,您必须考虑的另一件事是,如果您不处理异常(使用控制器建议或其他方式),您必须这样做,因为当您执行第一步时您将收到以下错误:

      • org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.HttpServerErrorException$InternalServerError

    我采用的解决方法是在CustomerController 中使用@ExceptionHandler 来测试您的代码(这不是执行此操作的最佳位置,具体取决于您在做什么。而是使用@ControllerAdvice。您可以找到一些这里的例子https://www.baeldung.com/exception-handling-for-rest-with-spring)。

    在用于重新创建案例的完整代码下方。

    Customer.class

    public class Customer {
        private Long id;
        private String name;
    
        public Customer(Long id, String name) {
            this.id = id;
            this.name = name;
        }
    
        // + getter and setter
    }
    

    CustomerController.class

    @RestController
    public class CustomerController {
    
        private final CustomerService customerService;
    
        public CustomerController(CustomerService customerService) {
            this.customerService = customerService;
        }
    
        @PostMapping(path = "/customers")
        public ResponseEntity<Customer> saveCustomer(@RequestBody Customer customer) {
            try {
                // Create the new product
                Customer savedCustomer = customerService.save(customer);
                // Build a created response
                return ResponseEntity
                        .created(new URI("/customers/" + savedCustomer.getId()))
                        .body(savedCustomer);
            } catch (URISyntaxException e) {
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
            }
        }
    
        // Code used to avoid the error explained in the second step
        @ExceptionHandler
        public ResponseEntity<?> handlingInternalServerError(HttpServerErrorException.InternalServerError ex) {
            // code to be executed when the exception is thrown (logs, ...)
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
    

    CustomerService.class

    @Service
    public class CustomerService {
    
        public Customer save(Customer customer) {
            return customer;
        }
    }
    

    CustomerControllerTest.class

    @SpringBootTest
    @AutoConfigureMockMvc
    class CustomerControllerTest {
    
        @MockBean
        private CustomerService customerService;
    
        @Autowired
        private MockMvc mockMvc;
    
        @Test
        @DisplayName("POST /customers - Failure")
        void saveCustomer() throws Exception {
    
            Customer customerMock = new Customer(1L, "John");
            // Setup mocked service
            when(customerService.save(any(Customer.class))).thenThrow(HttpServerErrorException.InternalServerError.class);
            RequestBuilder requestBuilder = post("/customers")
                    .content("{\"name\":\"John\"}")
                    .accept(MediaType.APPLICATION_JSON)
                    .contentType(MediaType.APPLICATION_JSON);
            MvcResult result = mockMvc.perform(requestBuilder).andReturn();
    
            MockHttpServletResponse response = result.getResponse();
    
            // Validate the response code and content type
            assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), response.getStatus());
        }
    }
    

    注意:此测试是使用 Java 8 和 JUnit5 执行的

    基于您的评论的其他注意事项: 好的。 @prabhakar-maity,根据您的情况,我的建议是使用 @ExceptionHandler 或 @ControllerAdvice 而不是 try...catch。例如,您的控制器或多个控制器中有 6 个方法,并且想要处理相同的异常(内部服务器错误)并返回相同的信息,因此您必须在每个方法中实现 try..catch,同时使用 @ ControllerAdive(多个控制器)或@ExceptionHandler(一个控制器)你在一个地方实现你的逻辑

    查看此问题以获取更多信息LINK

    【讨论】:

    • 看看,catch (URISyntaxException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); }我在这里发现了我的错误。将其更改为:} catch (URISyntaxException e) { return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT).build(); }catch (HttpServerErrorException.InternalServerError e){ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } 似乎有效
    猜你喜欢
    • 2018-12-05
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 2021-05-17
    • 2019-01-29
    • 1970-01-01
    相关资源
    最近更新 更多