使用Spring进行依赖注入的Jersey Web服务集成测试无法初始化@Context HttpServletRequest

时间:2016-10-07 14:14:15

标签: java spring integration-testing jersey-2.0 jersey-test-framework

我有使用spring进行依赖注入(spring-jersey模块)和hibernate进行对象关系映射(ORM)的jersey web服务。为了发展 集成测试考虑到以下条件:

  1. 仅为整个测试类启用测试容器一次
  2. 在测试中注册自定义侦听器,过滤器,servlet等 容器
  3. 确保 @Context HttpServletRequest不为空
  4. 根据这个https://java.net/jira/browse/JERSEY-2412泽西项目,JIRA任务 HttpServletRequest 为空,并且如任务的分辨率所示以设计为工作。 在Grizzly容器上运行集成测试时,它会在 http 服务器上运行集成测试,因此,依赖于基于servlet的功能 因为 HttpServletRequest,HttpServletResponse等不可用。

    似乎没有关于如何解决这个问题的标准解决方案,并且泽西社区显然对这些由贡献者开发的功能开放了 这张https://java.net/jira/browse/JERSEY-2417 JIRA票证中说明了这一点。在实现此功能之前,有哪些可行的解决方案?基于我的 研究我来了几篇文章:

    1. 使用外部容器(如果我不想要怎么办?)
    2. 使用jersey的码头模块(如果我不想使用Jetty怎么办?)
    3. 不适用于此项目的SpringMVC特定解决方案(因为我们不使用Spring MVC)
    4. 那么,在基于平针织物的Web服务器上成功运行集成测试的最佳解决方案是什么,该服务器使用spring-jersey网桥进行依赖注入并依赖于 基于Servlet的功能?

1 个答案:

答案 0 :(得分:0)

这是Jersey的标准行为,并允许基于servlet的功能,例如 HttpServletRequest 。根据我的研究, 我可以达到以下条件

  1. 仅为整个测试类启用测试容器一次
  2. 在测试中注册自定义侦听器,过滤器,servlet等     容器
  3. 确保@Context HttpServletRequest不为空
  4. 手动启动/停止灰熊容器,并在基于自定义平台的WebappContext上部署灰熊容器实例。步骤如下 如果有其他人遇到这样的问题

    1. 创建HttpServer
    2. 在@Before中创建一个反映您的自定义的 WebappContext web.xml 并使用 WebappContext
    3. 部署您的HttpServer实例
    4. 为了确保基于Servlet的等功能 在集成测试期间可以使用 HttpServletRequest 使用 ServletRegistration 在A Servlet容器中加载您的应用程序,如下所示
    5. 第1步

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(locations = { "classpath:applicationContext.xml" })
      public class ResourceEndpointIntegrationTest{
          @Context
          private HttpServletRequest httpReq;
      
          private static Logger logger = Logger.getLogger(ResourceEndpointIntegrationTest.class);
      
          public static final String BASE_URI = "http://localhost:8989/";
          private static HttpServer server = null;
      
          @BeforeClass
          public static void initTest() {
              RestAssured.baseURI = "http://localhost:8989/";
          }
      ...
      }
      

      使用 SpringJUnit4ClassRunner.class @ContextConfiguration 加载 applicationContext.xml 进行测试。同时声明 @Context HttpServletRequest 并创建 稍后将使用 HttpServer 的实例。我在这里使用 @BeforeClass 用于Rest-Assured特定目的(您不必使用它),它是可选的。

      第2步

      @Before
          public void setup() throws Exception {
              if (server == null) {
                  System.out.println("Initializing an instance of Grizzly Container ...");
                  final ResourceConfig rc = new ResourceConfig(ResourceEndpointIntegrationTest.class, ..., ..., ...); //update
      
                  WebappContext ctx = new WebappContext("IntegrationTestContext");
                              //register your listeners from web.xml in here
                  ctx.addListener("com.xxx.yyy.XEndpointServletContextListener");
                              //register your applicationContext.xml here
                  ctx.addContextInitParameter("contextConfigLocation", "classpath:applicationContext.xml");
      
                              //ServletRegistration is needed to load the ResourceConfig rc inside ServletContainer or you will have no 
                              //Servlet-based features available 
                  ServletRegistration registration = ctx.addServlet("ServletContainer",
                          new ServletContainer(rc));
      
                              //Initialize the Grizzly server passing it base URL
                  server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI));
      
                              //Deploy the server using our custom context
                  ctx.deploy(server);
              }
          }
      

      @Before 中的设置会针对每个测试运行,但if条件会强制设置方法的行为类似 @BeforeClass 允许我们初始化 服务器一次用于整个测试类减去 @BeforeClass 静态性质。

      我为测试类中的所有测试初始化​​服务器一次的原因是,如果我们不这样做,那么我们将拥有以下工作流程

      1. 启动服务器
      2. Spring开始扫描bean
      3. Spring自动装配
      4. Spring设置sessionFactory等。
      5. 运行测试
      6. Spring破坏了上下文
      7. 服务器已关闭
      8. 每次测试重复步骤#1至#7
      9. 以上是非常耗时且技术上不可行,因此初始化容器一次(这就是为什么我不扩展 JerseyTest 因为我想控制测试容器的启动/关闭) 。

        #Step 3

        @AfterClass
            public static void tearDown() throws Exception {
                System.out.println("Integration tests completed. Tear down the server ...");
                if (server != null && server.isStarted()) {
                    server.shutdownNow();
                    System.out.println("Grizzly instance shutdown completed");
                }
            }
        

        在第3步中,我们使用 @AfterClass 来关闭用于集成测试目的的grizzly实例。

        示例测试如下所示

        @Test
            public void testCreateSomethingReturnSuccessfully() {
                JSONObject something = new JSONObject();
                cust.put("name", "integrationTest");
                cust.put("age", 33);
        
                given().
                    contentType(ContentType.JSON).
                    body(something.toString()).post("/someEndpoint").
                then().
                    statusCode(200).
                assertThat().
                    body("id", greaterThan(0)).
                    body("name", equalTo("integrationTest")).
                    body("age", equalTo(33));
            }
        

        (Gradle)一些相关的堕落

        compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.23.2'
        compile group: 'org.glassfish.jersey.test-framework.providers', name:'jersey-test-framework-provider-grizzly2', version:'2.23.2'
        compile group: 'org.springframework', name:'spring-test', version:'4.3.2.RELEASE'
        compile group: 'io.rest-assured', name:'rest-assured', version:'3.0.1'
        
        
        // Spring
            compile group: 'org.springframework', name: 'spring-core', version: '4.3.2.RELEASE'
            compile group: 'org.springframework', name: 'spring-beans', version: '4.3.2.RELEASE'
            compile group: 'org.springframework', name: 'spring-web', version: '4.3.2.RELEASE'
            compile group: 'org.springframework', name: 'spring-jdbc', version: '4.3.2.RELEASE'
            compile group: 'org.springframework', name: 'spring-orm', version: '4.3.2.RELEASE'
        
            // Jersey-Spring bridge
            compile (group: 'org.glassfish.jersey.ext', name: 'jersey-spring3', version: '2.23.2'){
                exclude group: 'org.springframework', module: 'spring-core'
                exclude group: 'org.springframework', module: 'spring-web'
                exclude group: 'org.springframework', module: 'spring-beans'
                exclude group: 'org.springframework', module: 'spring-jdbc'
                exclude group: 'org.springframework', module: 'spring-orm'
            }
        

        部分导入

        import javax.servlet.http.HttpServletRequest;
        import javax.ws.rs.core.Context;
        
        import org.glassfish.grizzly.http.server.HttpServer;
        import org.glassfish.grizzly.servlet.ServletRegistration;
        import org.glassfish.grizzly.servlet.WebappContext;
        import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
        import org.glassfish.jersey.server.ResourceConfig;
        import org.glassfish.jersey.servlet.ServletContainer;
        
        import org.springframework.test.context.ContextConfiguration;
        import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;