【问题标题】:JUnit test starts Jetty, Jetty starts Spring, can test see spring application contextJUnit测试启动Jetty,Jetty启动Spring,可以测试看到spring应用上下文
【发布时间】:2012-03-23 03:45:39
【问题描述】:

这是针对我的整个系统的一些高级 Web/Rest 测试,这些测试由 Jetty/Spring 提供支持。

我想做的是进行一个完全独立的测试,

  • 启动启动应用程序的 Jetty
  • 应用程序启动 Spring
  • 测试使用 Webdriver / RestAssured 来命中应用程序和测试行为
  • 测试检查数据库是否有更改的数据

我想要做的是让整个事情在单个 JVM 中运行,即我正在启动一个 org.eclipse.jetty.server.Server。
这是因为它很简单,并且避免了具有外部依赖项的测试(例如启动 Jetty)

这一切都很酷,但我讨厌我必须手动检查数据库......我想使用我的 DAO(或者可能是服务层)类,所以我不会重新编写数据库代码。

由于我的 DAO 已经由 Spring 在与测试用例相同的 JVM 中的 Jetty 实例中启动,因此我想获取该 ApplicationContext,然后将我的 DAO bean 拉出。

我在获取 ApplicationContext 时有点卡住,因为测试不是一个“Spring”测试。

人们对如何做到这一点有任何想法?

【问题讨论】:

  • 为什么不在测试中构建另一个上下文并使用不同的 dao 类实例?您描述的场景听起来像是带有码头插件的 Maven 集成测试(故障安全插件)。
  • 谢谢,但我特意避免使用 Maven 插件作为实验,以使测试自包含...目前您可以像运行任何其他测试一样运行 junit 测试,而不需要 maven 或任何其他用于管理事物的构建工具......这来自许多使用 Maven 集成测试模型的项目所经历的痛苦。我可能会将其移至 Gradle,这样我可以在不同类型的测试之间进行比 maven 提供的更多的分离。

标签: java spring jetty


【解决方案1】:

我认为在jetty中正常启动的spring上下文是无法访问的,如果你使用一些嵌入式服务器可能会工作。

但我认为有更简单的解决方案:

  • 为测试使用第二个(不同的)spring 上下文,这可能比“正常”的要小,因为您不需要所有的服务和控制器,或者
  • 在您的服务器中添加一些 json 或 webservice 查询接口,它只是从数据库中返回请求的结果。然后,您可以通过服务器中的该接口从测试中访问数据库。 -- 我认为每个实体只需要两个或三个不同的查询,所以工作量应该不大,(但我更喜欢其他解决方案)。

【讨论】:

  • 感谢@Ralph,当应用服务器实例位于与测试不同的 JVM 中时,我曾在不同的项目中使用过这两种方法。但是因为我在同一个 JVM 中启动 Jetty,所以我很想知道 Spring 中是否有我可以使用的钩子。第一个选项工作正常,但仅用于连接到数据库等共享资源。假设我需要为内存中的东西连接到服务层,然后第一个选项就失败了。第二种选择是更多的努力,我试图通过在一个 JVM 中运行所有东西来避免。
  • 你也可以在 Arquillian jboss.org/arquillian 上锁 - 我不知道它是否对这个场景有帮助,但它可以以某种方式将测试与 EJB/CDI 容器连接起来,也许它可以与 spring 一起使用也是。
  • 没有使用 Arquillian,因为我不做 EJB/CDI 的东西,而且我永远不会使用 JBoss。锁定它,因为它是迄今为止最好的答案......目前我正在使用第一个解决方案,它工作正常,如果我想使用远程码头实例(我可以用系统道具控制)。我仍然想弄清楚我是否可以连接到同一个应用程序上下文,就像暂时的思考练习一样。
【解决方案2】:

@Ralph 的答案是最好的 - 使用单独的弹簧上下文进行测试。理想情况下,您应该将所有 DAO bean 及其依赖项重构为一个单独的 dao-beans.xml,您可以将其包含在您的主应用程序上下文和测试上下文中。..

或者,您可以使用 Spring Remoting 通过 RMI 或 HTTP 从 Jetty 服务器导出 DAO bean,方法是将 ServiceExporter bean 添加到您的(真实)应用上下文中

<bean name="daoExporter"
        class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
    <property name="service">
        <ref bean="dao" />
    </property>
    <property name="serviceInterface" value="com.example.IDao" />
</bean>

以及 web.xml 中的自定义 Spring 远程处理 servlet

<servlet>
    <servlet-name>daoServiceExporter</servlet-name>
    <servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>daoServiceExporter</servlet-name>
    <url-pattern>/remoting/dao</url-pattern>
</servlet-mapping>

然后将其导入您的测试上下文中

<bean id="dao" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
    <property name="serviceInterface" value="com.example.IDao" />
    <property name="serviceUrl" value="http://localhost:8080/remoting/dao"/>
</bean>

这只是一个更好的答案,例如加载 Spring 上下文需要很长时间,或者您可能有一些必须保持单例的 bean。

【讨论】:

  • +1 表示使用 Spring Remoting 的想法,这比我的“手写”json 想法要好。
  • 不错的解决方案,类似于上面的评论,DAO 通常很容易在单独的 Spring 应用程序上下文中启动,因为它们只共享一个 DB。但这将是导出服务的好方法,可能涉及的不仅仅是数据库。
猜你喜欢
  • 1970-01-01
  • 2017-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-05
  • 2019-11-09
相关资源
最近更新 更多