【问题标题】:Write JUnit test for @ExceptionHandler为 @ExceptionHandler 编写 JUnit 测试
【发布时间】:2013-01-14 08:16:12
【问题描述】:

我正在使用 Spring MVC 编写一个 Rest 服务。以下是课程大纲:

 @Controller
 public class MyController{

     @RequestMapping(..)
     public void myMethod(...) throws NotAuthorizedException{...}

     @ExceptionHandler(NotAuthorizedException.class)
     @ResponseStatus(value=HttpStatus.UNAUTHORIZED, reason="blah")
     public void handler(...){...}
 }

我已经使用here 发布的设计编写了我的单元测试。测试基本如下:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(....)
public class mytest{

    MockHttpServletRequest requestMock;
    MockHttpServletResponse responseMock;
    AnnotationMethodHandlerAdapter handlerAdapter;

@Before
public void setUp() {
    requestMock = new MockHttpServletRequest();
    requestMock.setContentType(MediaType.APPLICATION_JSON_VALUE);
    requestMock.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);

    responseMock = new MockHttpServletResponse();

    handlerAdapter = new AnnotationMethodHandlerAdapter();
}

@Test
public void testExceptionHandler(){
    // setup ....
    handlerAdapter.handle(...);

    // verify
    // I would like to do the following
    assertThat(responseMock.getStatus(), is(HttpStatus.UNAUTHORIZED.value()));
}

}

但是,对handle 的调用正在抛出NotAuthorizedException。我已经读到这是设计使然能够对方法抛出适当的异常进行单元测试,但是我想编写一个自动化测试框架正在适当地处理这个异常并且被测试的类已经适当地实现了处理程序.有没有办法做到这一点?

请注意,我无法在可以发布的地方访问实际代码。

另外,我仅限于(由于不幸的原因)Spring 3.0.5 或 3.1.2。

【问题讨论】:

  • 一般来说,我会说测试你自己的代码,而不是框架。
  • 我建议测试@ExceptionHandler 的存在并且我已经通过自动化测试正确配置了框架是有价值的。
  • 当然可以,但这可能超出了单元测试的范围。回想一下,除了您的 jUnit 测试之外,您还需要一个正确设置的 spring 配置文件。另外,升级 Spring 后,您的测试可能必须更改。一般来说,我发现如果我正确配置了一次框架,我倾向于在任何地方都正确配置它,否则当我尝试部署我的应用程序时会立即发生一些快速失败。
  • 您可能还认为框架本身具有详尽的单元测试套件,可供您随时查看。
  • 我建议我要测试的不是框架,而是我正确设置了注释。这就是使用AnnotationMethodHandlerAdapter@RequestMapping 的情况下的锥体。我正在寻找对我的@ExceptionHandler 注释进行相同类型的测试,这是一种自动测试,相应的响应代码与相应的消息一起返回。这不是测试框架,而是测试我的代码。我可以进行反思以查找类中的注释并检查它们是否正确,但似乎应该有更好的方法。

标签: java spring rest spring-mvc junit


【解决方案1】:

使用@ControllerAdvice 而不是@Controller 注释您的异常处理控制器。

正如 Boris Treukhov 在将 @ExceptionHandler 注释添加到控制器中抛出异常的方法时所指出的那样,它将使其工作,但只能从该特定控制器工作。

@ControllerAdvice 将允许您的异常处理方法适用于您的整个应用程序,而不仅仅是一个特定的控制器。

【讨论】:

    【解决方案2】:

    考虑使用 Spring 3.2 及其mvc-test-framework

    import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @ContextConfiguration("file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml")
    public class WebMvcTest {
    
        @Autowired
        private WebApplicationContext wac;
    
        private MockMvc mockMvc;
    
        @Before
        public void setup() {
            this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
        }
    
        @Test
        public void getFoo() throws Exception {
            this.mockMvc.perform(
                get("/testx")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                )
                .andExpect(status().isUnauthorized());
        }
    }
    

    控制器代码

    @Controller
    public class MyController {
    
        public class MyException extends RuntimeException {
        };
    
        @RequestMapping("/testx")
        public void myMethod() {
            throw new MyException();
    
        }
    
        @ExceptionHandler(MyException.class)
        @ResponseStatus(value = HttpStatus.UNAUTHORIZED, reason = "blah")
        public void handler() {
            System.out.println("handler processed");
        }
    }
    

    这个“测试”顺利通过。

    免责声明:目前我是 Spring MVC 测试的新手,实际上这是我的第一次测试。
    更新:感谢 The Drake the correction

    【讨论】:

    • 这看起来是正确的解决方案。谢谢你。不幸的是,我仅限于 Spring 3.0.5。如果没有人提出我可以与该版本一起使用的解决方案,我会将其标记为正确答案。
    • 这对我不起作用我正在使用MockMvcBuilders.standaloneSetup()
    【解决方案3】:

    您可以将@Test 更改为

    @Test(expected=NotAuthorizedException.class)
    

    如果内部抛出异常,则返回 true,否则返回 false。

    这也会使 assertThat() 变得不必要。您可以编写第二个测试来捕获 NotAuthorizedException,然后您可以在该条件下检查 responseMock。

    【讨论】:

    • 我已经在使用ExpectedException 规则来执行此操作。这只是在抛出异常时允许测试通过,它不会测试框架是否正确地将异常传递给@ExceptionHandler 方法。
    • 如果您使用的是 ExpectedException 规则,则它不会出现在您发布的帖子中的任何地方,最好在此处列出。就像@flup 说的那样,测试你自己的代码,而不是框架。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-27
    • 2021-02-03
    • 1970-01-01
    • 2022-11-04
    • 2012-04-02
    • 1970-01-01
    • 2022-11-03
    相关资源
    最近更新 更多