【发布时间】:2012-06-22 15:05:52
【问题描述】:
我为一些 Spring MVC 控制器编写 JUnit 测试。 JUnit 测试的初始化对于我所有的 Controller 测试都是通用的,所以我想创建一个抽象类来执行此初始化。
因此,我创建了以下代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:spring/applicationContext-test.xml", "classpath*:spring/spring-mvc-test.xml" })
@Transactional
public abstract class AbstractSpringMVCControllerTest<T> {
@Autowired
protected ApplicationContext applicationContext;
protected MockHttpServletRequest request;
protected MockHttpServletResponse response;
protected HandlerAdapter handlerAdapter;
protected T controller;
@SuppressWarnings("unchecked")
@Before
public void initContext() throws SecurityException, NoSuchFieldException {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
handlerAdapter = applicationContext.getBean(AnnotationMethodHandlerAdapter.class);
// Does not work, the problem is here...
controller = applicationContext.getBean(T);
}
}
这个想法是为每个我想测试的控制器创建一个扩展我的AbstractSpringMVCControllerTest 的 JUnit 测试类。 extends 声明中给出的类型是 Controller 的类。
例如,如果我想测试我的AccountController,我将像这样创建AccountControllerTest 类:
public class AccountControllerTest extends AbstractSpringMVCControllerTest<AccountController> {
@Test
public void list_accounts() throws Exception {
request.setRequestURI("/account/list.html");
ModelAndView mav = handlerAdapter.handle(request, response, controller);
...
}
}
我的问题出在抽象类的initContext()方法的最后一行。这个抽象类将controller对象声明为T对象,但是怎么能告诉Spring Application Context返回T类型的bean呢?
我尝试过类似的方法:
Class<?> controllerClass = this.getClass().getSuperclass().getDeclaredField("controller").getType();
controller = (T) applicationContext.getBean(controllerClass);
但 controllerClass 返回的是 java.lang.Object.class 类,而不是 AccountController.class。
当然,我可以创建一个public abstract Class<?> getControllerClass(); 方法,该方法将被每个 JUnit Controller 测试类覆盖,但我更愿意避免这种解决方案。
那么,有什么想法吗?
【问题讨论】:
-
如果您对问题标题有更好的想法,请不要犹豫:)
-
欢迎来到java类型擦除噩梦。
-
是的,我完全忘记了我(再次)遇到了这种类型的擦除。
-
不工作吗?我猜不是,如果它是运行时的事情....实际上,现在我想起来了,当我遇到类似的问题时,我最终做了一些与您的
public abstract Class<?> getControllerClass();解决方案非常相似的事情,尽管我所做的是将类名存储为字符串并使用Class.forName()获取类。
标签: java spring generics spring-mvc