【问题标题】:Testing Spring managed servlet测试 Spring 托管 servlet
【发布时间】:2014-04-10 10:59:23
【问题描述】:

我需要测试一个 servlet,它现在工作正常。

servlet 需要使用 Spring 服务,因此对其进行了修改:

SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(
    this, config.getServletContext()); // ImageServlet.java line 49

迁移到 Spring 4 后,测试中断,目前抛出此异常:

java.lang.IllegalStateException:
No WebApplicationContext found: no ContextLoaderListener registered?
at org.springframework.web.context.support.WebApplicationContextUtils.
    getRequiredWebApplicationContext(WebApplicationContextUtils.java:84)
at org.springframework.web.context.support.SpringBeanAutowiringSupport.
    processInjectionBasedOnServletContext(SpringBeanAutowiringSupport.java:107)
at package.ImageServlet.init(ImageServlet.java:49)
at in.nasv.utils.ImageServletTest.accessingImageViaHttp(ImageServletTest.java:45)

这是 ImageServletTest 的部分代码:

// prepare servlet instance
MockServletConfig config = new MockServletConfig(
    new MockServletContextPatched());
ImageServlet servlet = new ImageServlet();
servlet.init( config ); // ImageServletTest, line 45

而这个打补丁的类(现在实际上并没有打补丁):

public class MockServletContextPatched extends MockServletContext{ }

我应该怎么做才能避免这种“IllegalStateException:未找到 WebApplicationContext:未注册 ContextLoaderListener?” ?

【问题讨论】:

  • 你真的需要调用init() 方法来测试你的Servlet吗?如果没有,我建议您只实例化您的 Servlet 并手动注入其依赖项,而不是在测试中依赖 SpringBeanAutowiringSupport
  • 很好的方法,但不适用于我的情况。 Spring MockServletContext 的功能非常有限(没有 setter 和 getter 只返回固定值,虚拟 Spring!)所以我需要扩展它。我只能通过 init() 应用它
  • Spring 的MockServletContext 确实有二传手。您认为 Spring 的MockServletContext 有哪些限制?您的自定义 MockServletContextPatched 有什么特别之处?
  • 我需要 MimeType 的 setter,但只有 getter 存在。我的 MockServletContextPatched 扩展了这个。是的,MockServletContext 有 3 个额外的 setter,但许多其他的没有 - 限制 Spring 模拟类的功能。
  • MockServletContext 中没有用于 MIME 类型的 setter 方法,因为 Spring 使用 Java 激活框架来解析传递给 getMimeType(String) 的文件名的 MIME 类型。如果您需要一种方法来设置 Java 激活框架不支持的自定义 MIME 类型,请针对“Spring Framework”项目和“测试”组件创建一个新的 JIRA 问题以请求该功能。

标签: java spring servlets spring-test


【解决方案1】:

我找到了解决方案。但足够清楚,但有一个解决方案。

现在 servlet 初始化是:

MockServletContext servletContext = new MockServletContextPatched();
MockServletConfig config = new MockServletConfig( servletContext );
ImageServlet servlet = new ImageServlet();

ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext( "spring-data-app-context.xml" );
DefaultListableBeanFactory dlbf = new DefaultListableBeanFactory(appContext.getBeanFactory());
GenericWebApplicationContext gwac = new GenericWebApplicationContext(dlbf);        
servletContext.setAttribute(GenericWebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, gwac);
gwac.setServletContext(servletContext);
gwac.refresh();

servlet.init( config );

以标准方式准备请求和响应:

MockHttpServletResponse response = new MockHttpServletResponse();

URL serverUrl = new URL( propertyExtendedService.getServerAddress(true) );
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI( "/what-you-want" );
request.setPathInfo( "/" + TEST_IMAGE );
request.setContentType("image/jpeg");
request.addHeader("Accept", "image/jpeg;image/jpg;" );

最后一步是调用过滤器并断言返回值:

servlet.doGet( request, response );
assertEquals( response.getStatus(), 200 );
// assert everything you want

【讨论】:

  • 你绝对不应该加载两个ApplicationContexts。一个就够了。此外,Spring TestContext Framework 已经为您设置了WebApplicationContext 的测试基础架构(包括MockServletContextMockHttpServletRequestMockHttpServletResponse)。你看过那个吗?
【解决方案2】:

更新updated documentation for getServletContext() 现已上线。


不必仅仅为了在 Spring 的 MockServletContext 中配置自定义 MIME 类型而实现自定义 MockServletContextPatched 类。

由于 Spring 的 MockServletContext 使用 Java Activation Framework (JAF) 来实现 ServletContext.getMimeType(String) 方法,因此通过 JAF 的 MimetypesFileTypeMap.addMimeTypes(String) 方法配置自定义 MIME 类型非常容易,如下所示。

MockServletContext mockServletContext = new MockServletContext();
MimetypesFileTypeMap mimetypesFileTypeMap =
    (MimetypesFileTypeMap) MimetypesFileTypeMap.getDefaultFileTypeMap();
mimetypesFileTypeMap.addMimeTypes("text/enigma    enigma");
assertEquals("text/enigma", mockServletContext.getMimeType("filename.enigma"));

在上面基于 JUnit 的测试代码中,我为扩展名为 .enigma 的文件配置了自定义 MIME 类型 "text/enigma"

希望这会有所帮助!

问候,

Sam(Spring TestContext 框架的作者)

附言我创建了 JIRA 问题 SPR-12126 以改进 MockServletContext 的文档。

【讨论】:

  • 嗨,山姆。感谢您为我的解决方法提供的解决方案。抱歉,我放弃了这个测试(所有旧的 servlet 功能都被放弃了,所以它的测试也被放弃了),所以我可以测试它。您的方法似乎是一种优雅的方法。但是...
  • 但我不确定它是否更好。大多数开发人员会寻找一个 setter,因为常见的测试替身很简单并且具有硬编码的值。其他原因是 JAF 似乎并不为人所知,所以可能 MimetypesFileTypeMap 会被跳过。但这是我的看法,我错了。再次 10 倍的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-21
  • 2014-01-25
  • 1970-01-01
  • 2016-04-07
  • 2020-03-11
  • 1970-01-01
相关资源
最近更新 更多