0

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

  1. 对整个测试类只初始化一次测试容器
  2. 将自定义侦听器、过滤器、servlet 等注册到测试容器
  3. 确保@Context HttpServletRequest 不为空

根据这个https://java.net/jira/browse/JERSEY-2412 Jersey 项目 JIRA 任务HttpServletRequest为空,这在任务Works as desgined的解决方案中显示。在 Grizzly 容器上运行集成测试时,它会在http服务器上运行集成测试,因此,对HttpServletRequest、HttpServletResponse 等基于 servlet 的功能的任何依赖都不可用。

似乎没有关于如何解决这个问题的标准解决方案,泽西社区显然对贡献者正在开发的这些功能持开放态度,如https://java.net/jira/browse/JERSEY-2417 JIRA 票中所述。在实施此功能之前,有哪些可能的解决方法?根据我的研究,我遇到了一些声明:

  1. 使用外部容器(如果我不想要怎么办?)
  2. 使用 jersey 的 jetty 模块(如果我不想使用 Jetty 怎么办?)
  3. 不适用于本项目的 SpringMVC 特定解决方案(因为我们不使用 Spring MVC)

那么,在使用 spring-jersey 桥接器进行依赖注入并依赖基于 Servlet 的功能的基于 jersey 的 Web 服务器上成功运行集成测试的最佳解决方案是什么?

4

1 回答 1

0

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

  1. 对整个测试类只初始化一次测试容器
  2. 将自定义侦听器、过滤器、servlet 等注册到测试容器
  3. 确保 @Context HttpServletRequest 不为空

通过手动启动/停止 grizzly 容器并将 grizzly 容器实例部署在基于自定义球衣的 WebappContext 上。步骤如下,以防其他人遇到此类问题

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

步骤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

以上非常耗时且技术上不可行,因此初始化容器一次(这就是我不扩展JerseyTest的原因,因为我想控制测试容器的启动/关闭)。

#步骤 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;
于 2016-10-07T14:19:58.110 回答