Java MockMVC如何在同一测试用例中测试异常和响应代码

Java MockMVC如何在同一测试用例中测试异常和响应代码,java,spring,testing,spring-mvc,junit,Java,Spring,Testing,Spring Mvc,Junit,我想断言引发了异常,并且服务器返回500个内部服务器错误 为了突出显示意图,提供了一个代码段: thrown.expect(NestedServletException.class); this.mockMvc.perform(post("/account") .contentType(MediaType.APPLICATION_JSON) .content(requestString)) .andExpect(status

我想断言引发了异常,并且服务器返回500个内部服务器错误

为了突出显示意图,提供了一个代码段:

thrown.expect(NestedServletException.class);
this.mockMvc.perform(post("/account")
            .contentType(MediaType.APPLICATION_JSON)
            .content(requestString))
            .andExpect(status().isInternalServerError());
当然,如果我写
isInternalServerError
isOk
,这并不重要。 无论是否在
throw.except
语句下面抛出异常,测试都将通过


您将如何着手解决此问题?

您可以尝试以下方法-

  • 创建自定义匹配器

    public class CustomExceptionMatcher extends
    TypeSafeMatcher<CustomException> {
    
    private String actual;
    private String expected;
    
    private CustomExceptionMatcher (String expected) {
        this.expected = expected;
    }
    
    public static CustomExceptionMatcher assertSomeThing(String expected) {
        return new CustomExceptionMatcher (expected);
    }
    
    @Override
    protected boolean matchesSafely(CustomException exception) {
        actual = exception.getSomeInformation();
        return actual.equals(expected);
    }
    
    @Override
    public void describeTo(Description desc) {
        desc.appendText("Actual =").appendValue(actual)
            .appendText(" Expected =").appendValue(
                    expected);
    
    }
    }
    
  • 在测试用例中使用自定义匹配器作为-

    exception.expect(CustomException.class);
    exception.expect(CustomException
            .assertSomeThing("Some assertion text"));
    this.mockMvc.perform(post("/account")
        .contentType(MediaType.APPLICATION_JSON)
        .content(requestString))
        .andExpect(status().isInternalServerError());
    
  • p.S.:我提供了一个通用伪代码,您可以根据自己的要求进行自定义。

    在控制器中:

    throw new Exception("Athlete with same username already exists...");
    
    在您的测试中:

        try {
            mockMvc.perform(post("/api/athlete").contentType(contentType).
                    content(TestUtil.convertObjectToJsonBytes(wAthleteFTP)))
                    .andExpect(status().isInternalServerError())
                    .andExpect(content().string("Athlete with same username already exists..."))
                    .andDo(print());
        } catch (Exception e){
            //sink it
        }
    

    您可以获取对和可能已解决的异常的引用,并使用通用JUnit断言进行检查

    MvcResult result = this.mvc.perform(
            post("/api/some/endpoint")
                    .contentType(TestUtil.APPLICATION_JSON_UTF8)
                    .content(TestUtil.convertObjectToJsonBytes(someObject)))
            .andDo(print())
            .andExpect(status().is4xxClientError())
            .andReturn();
    
    Optional<SomeException> someException = Optional.ofNullable((SomeException) result.getResolvedException());
    
    someException.ifPresent( (se) -> assertThat(se, is(notNullValue())));
    someException.ifPresent( (se) -> assertThat(se, is(instanceOf(SomeException.class))));
    
    MvcResult result=this.mvc.perform(
    post(“/api/some/endpoint”)
    .contentType(TestUtil.APPLICATION\u JSON\u UTF8)
    .content(TestUtil.convertObjectToJsonBytes(someObject)))
    .andDo(print())
    .andExpect(状态().is4xxClientError())
    .andReturn();
    Optional someException=Optional.ofNullable((someException)result.getResolvedException());
    ifPresent((se)->assertThat(se,is(notNullValue()));
    ifPresent((se)->assertThat(se,is(instanceOf(someException.class)));
    
    如果您有一个异常处理程序,并且希望测试特定的异常,那么您还可以断言实例在已解决的异常中有效

    .andExpect(result -> assertTrue(result.getResolvedException() instanceof WhateverException))
    

    我最近遇到了相同的错误,我没有使用MockMVC,而是创建了一个集成测试,如下所示:

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @ContextConfiguration(classes = { MyTestConfiguration.class })
    public class MyTest {
        
        @Autowired
        private TestRestTemplate testRestTemplate;
        
        @Test
        public void myTest() throws Exception {
            
            ResponseEntity<String> response = testRestTemplate.getForEntity("/test", String.class);
            
            assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode(), "unexpected status code");
            
        }   
    }
    
    @SpringBootTest(webEnvironment=SpringBootTest.webEnvironment.RANDOM\u端口)
    @ContextConfiguration(类={MyTestConfiguration.class})
    公共类MyTest{
    @自动连线
    私有TestRestTemplate TestRestTemplate;
    @试验
    public void myTest()引发异常{
    ResponseEntity response=testrestemplate.getForEntity(“/test”,String.class);
    assertEquals(HttpStatus.INTERNAL_SERVER_ERROR,response.getStatusCode(),“意外状态代码”);
    }   
    }
    

    @配置
    @EnableAutoConfiguration(exclude=NotDesiredConfiguration.class)
    公共类MyTestConfiguration{
    @RestController
    公共类测试控制器{
    @GetMapping(“/test”)
    public ResponseEntity get()引发异常{
    抛出新异常(“不好”);
    }           
    }   
    }
    

    这篇文章非常有帮助:

    这样,不管状态代码或响应如何,测试都会通过。如果您希望测试中出现异常,您可以使用
    assertTrue(result.getResolvedException()instanceof SomeException)
    非常好的一个!!真干净整洁!为我节省了一辈子的麻烦:)更具体地说,为了使用
    MvcResult.perform(…).andExpect()
    @Controller
    中出现异常时,您需要将
    @ExceptionHandler
    注入到您的Spring测试上下文中,或者它在
    .perform()
    中正好在
    .andExpect()之前抛出异常
    ))谢谢大副!
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @ContextConfiguration(classes = { MyTestConfiguration.class })
    public class MyTest {
        
        @Autowired
        private TestRestTemplate testRestTemplate;
        
        @Test
        public void myTest() throws Exception {
            
            ResponseEntity<String> response = testRestTemplate.getForEntity("/test", String.class);
            
            assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode(), "unexpected status code");
            
        }   
    }
    
    @Configuration
    @EnableAutoConfiguration(exclude = NotDesiredConfiguration.class)
    public class MyTestConfiguration {
        
        @RestController
        public class TestController {
            
            @GetMapping("/test")
            public ResponseEntity<String> get() throws Exception{
                throw new Exception("not nice");
            }           
        }   
    }