编写针对@ExceptionHandler的JUnit测试

13

我正在使用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(...){...}
 }

我已经根据此处发布的设计编写了单元测试。测试基本上如下所示:

@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。

6
通常来说,我会建议您测试自己的代码,而不是测试框架。 - flup
1
我建议通过自动化测试来检测@ExceptionHandler的存在,并验证我是否正确配置了框架,这是非常有价值的。 - John B
1
当然可以,但这可能超出了单元测试的范围。请记住,除了jUnit测试之外,您还需要一个正确设置的Spring配置文件。此外,一旦您升级Spring,您的测试可能会发生变化。一般来说,我发现如果我已经正确配置了框架一次,我 tend to either configure it correctly everywhere, or else there's some fail fast that happens immediately when I try to deploy my app. - Peter Bratton
您还可以考虑到该框架本身具有详尽的单元测试套件,可随时供您检查。 - Peter Bratton
我建议测试的不是框架,而是我的注释是否设置正确。这就是使用AnnotationMethodHandlerAdapter处理@RequestMapping时所做的。我正在寻找对我的@ExceptionHandler注释进行同样类型的测试,即自动化测试适当的响应代码是否与适当的消息返回。这不是测试框架,而是我的代码。我可以使用反射查找类中的注释并检查它们是否正确,但似乎应该有更好的方法。 - John B
3个回答

9

考虑使用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对更正的贡献。


这看起来是正确的解决方案。谢谢你。不幸的是,我只能使用Spring 3.0.5版本。如果没有人提供可以在该版本中使用的解决方案,我会将其标记为正确答案。 - John B
这对我不起作用,我正在使用MockMvcBuilders.standaloneSetup() - Foolish

2

将您的异常处理控制器注释为@ControllerAdvice而不是@Controller

正如Boris Treukhov在向控制器方法添加@ExceptionHandler注释时所指出的那样,这将使其工作,但仅限于特定控制器。

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


-2
你可以将 @Test 改为:
@Test(expected=NotAuthorizedException.class)

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

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


我已经在使用ExpectedException规则来实现这个。这只是允许测试在异常抛出时通过,它并没有测试框架是否正确地将异常传递给@ExceptionHandler方法。 - John B
如果您正在使用ExpectedException规则,则它并未在您发布的帖子中列出,因此最好在那里列出。就像@flup所说的那样,测试您自己的代码,而不是框架。 - Joe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接