如何使用 @PathVariable 对 Spring MVC 控制器进行单元测试?
我有一个与此类似的简单带注释的控制器:
@Controller
public class MyController {
@RequestMapping("/{id}.html")
public String doSomething(@PathVariable String id, Model model) {
// do something
return "view";
}
}
我想用这样的单元测试来测试它:
public class MyControllerTest {
@Test
public void test() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("/test.html");
new AnnotationMethodHandlerAdapter()
.handle(request, new MockHttpServletResponse(), new MyController());
// assert something
}
}
问题是 AnnotationMethodHandlerAdapter.handler() 方法抛出异常:
java.lang.IllegalStateException: Could not find @PathVariable [id] in @RequestMapping
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.resolvePathVariable(AnnotationMethodHandlerAdapter.java:642)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolvePathVariable(HandlerMethodInvoker.java:514)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:262)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:146)
I have a simple annotated controller similar to this one:
@Controller
public class MyController {
@RequestMapping("/{id}.html")
public String doSomething(@PathVariable String id, Model model) {
// do something
return "view";
}
}
and I want to test it with an unit test like this:
public class MyControllerTest {
@Test
public void test() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("/test.html");
new AnnotationMethodHandlerAdapter()
.handle(request, new MockHttpServletResponse(), new MyController());
// assert something
}
}
The problem is that AnnotationMethodHandlerAdapter.handler() method throws an exception:
java.lang.IllegalStateException: Could not find @PathVariable [id] in @RequestMapping
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.resolvePathVariable(AnnotationMethodHandlerAdapter.java:642)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolvePathVariable(HandlerMethodInvoker.java:514)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:262)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:146)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我会根据 Spring 参考手册中的术语将您的集成测试称为集成测试。怎么样做类似的事情:
有关更多信息,我写了 有关集成测试 Spring MVC 注释的博客条目。
I'd call what you're after an integration test based on the terminology in the Spring reference manual. How about doing something like:
For more information I've written a blog entry about integration testing Spring MVC annotations.
从 Spring 3.2 开始,有一种适当的方法来测试这一点,以一种优雅而简单的方式。您将能够执行以下操作:
有关更多信息,请查看 http://blog.springsource.org/2012/11/12/spring-framework-3-2-rc1-spring-mvc-test-framework/
As of Spring 3.2, there is a proper way to test this, in an elegant and easy way. You will be able to do things like this:
For further information, take a look at http://blog.springsource.org/2012/11/12/spring-framework-3-2-rc1-spring-mvc-test-framework/
一个有前途的 Spring MVC 测试框架
https://github.com/SpringSource/spring-test-mvc
A promising framework for testing Spring MVC
https://github.com/SpringSource/spring-test-mvc
异常消息引用了“feed”变量,该变量不存在于您的示例代码中,它可能是由您未向我们展示的某些内容引起的。
另外,您的测试正在测试 Spring 和您自己的代码。这真的是你想做的吗?
最好假设 Spring 可以工作(确实如此),然后测试您自己的类,即直接调用
MyController.doSomething()
。这是注释方法的好处之一 - 您不需要使用模拟请求和响应,只需使用域 POJO。The exception message refers to a "feed" variable, which isn't present in your sample code, it's likely being caused by something you haven't shown us.
Also, your test is testing Spring and your own code. Is this really what you want to do?
It's better to assume that Spring works (which it does), and just test your own class, i.e. call
MyController.doSomething()
directly. That's one benefit of the annotation approach - you don't need to use mock requests and responses, you just use domain POJOs.我发现您可以手动将 PathVariable 映射插入到请求对象中。这显然不理想,但似乎可行。在您的示例中,类似于:
我肯定有兴趣寻找更好的选择。
I've found that you can manually insert a PathVariable mapping into the request object. This is distinctly non-ideal but appears to work. In your example, something like:
I'd definitely be interested in finding a better option.
假设您使用的是 Spring 3.0.x。
在这里,我建议使用 spring-test 而不是 spring-test-mvc 合并 Emil 和 scrapa05 答案。如果您使用 Spring 3.2.x 或更高版本,请跳过此答案并参考 spring-test-mvc 示例
MyControllerWithParameter.java
MyControllerTest.java
}
Provided you are using Spring 3.0.x.
Here I suggest a merger of Emil and scarba05 answers using spring-test not spring-test-mvc. Please skip this answer and refer to spring-test-mvc examples if you are using Spring 3.2.x or later
MyControllerWithParameter.java
MyControllerTest.java
}
我不确定我原来的答案是否会对@PathVariable 有帮助。我刚刚尝试测试 @PathVariable ,但出现以下异常:
org.springframework.web.bind.annotation.support.HandlerMethodInitationException: 无法调用处理程序方法 [public org.springframework.web.servlet.ModelAndView test.MyClass. myMethod(test.SomeType)];嵌套异常是 java.lang.IllegalStateException: Could not find @PathVariable [parameterName] in @RequestMapping
原因是请求中的路径变量被拦截器解析。以下方法对我有用:
我在 集成测试 spring mvc 注解
I'm not sure my original answer is going to help with @PathVariable. I've just tried testing an @PathVariable and I get the following exception:
org.springframework.web.bind.annotation.support.HandlerMethodInvocationException: Failed to invoke handler method [public org.springframework.web.servlet.ModelAndView test.MyClass.myMethod(test.SomeType)]; nested exception is java.lang.IllegalStateException: Could not find @PathVariable [parameterName] in @RequestMapping
The reason is that the path variables in the request get parsed by an interceptor. The following approach works for me:
I've add a new blog post on integration testing spring mvc annotations