如何在测试类中为所有测试启动Jersey测试容器(Grizzly)一次?

我正在努力修复其中一个项目中的集成测试。 目前,所有集成测试类都扩展了JerseyTest类。 通过JerseyTest类,我意识到它使用Junit的Before和After注释为每个测试方法启动和停止容器。

为什么这有必要? 如果我们提起容器一次,运行测试并在结束时将其关闭,这还不够吗?

我们也使用Spring,上下文初始化需要时间。

在Junit4之前,我们通过使用布尔标志手动处理它来解决这个限制。

@Before public void setup() { if(!containerStarted) { // start containerStarted = true; } // else do nothing } 

您可以使用@BeforeClass和@AfterClass来覆盖JerseyTest的@Before和@After生命周期。 这是代码模板:

 public abstract class MyJerseyTest { private JerseyTest jerseyTest; public MyJerseyTest(){ } @BeforeClass public void setUp() throws Exception { initJerseyTest() jerseyTest.setUp(); } @AfterClass public void tearDown() throws Exception { jerseyTest.tearDown(); } private void initJerseyTest() { jerseyTest = new JerseyTest() { @Override protected Application configure() { // do somthing like enable(...); set(...); // create ResourceConfig instance ResourceConfig rc = new ResourceConfig(); // do somthing like rc.property(...); rc.register(...); return rc; } }; } } 

希望这有用。

我们有类似的情况,使用jersey加弹簧作为dependency injection框架(jersey-spring-bridge)。 使用JerseyTest框架编写集成测试很棘手,因为它在测试之前启动容器并在测试之后停止容器。 这种方法可能有一个优势,但考虑到spring每次都会扫描和自动assemblybean这一事实,它非常耗时且棘手。

如何初始化一个灰熊容器并将其用于测试类中的所有测试?

为实现上述目标,我按照以下步骤操作:

在测试类中作为实例变量,声明HttpServer的实例如下

 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:applicationContext.xml" }) public class OrderResourceTest { ... public static final String BASE_URI = "http://localhost:8989/"; private static HttpServer server = null; ... ... } 

请注意,我不使用JerseyTest因为我想自己处理测试容器的启动/停止。 现在,您需要使用@Before@AfterClass来设置服务器实例。 在@Before我们将设置server实例,以便在web.xml加载我们的自定义filter/侦听器定义(例如以编程方式将web.xml加载到server实例中)

 @Before public void setUp() throws Exception { if (server == null) { System.out.println("Initializing an instance of Grizzly Container"); final ResourceConfig rc = new ResourceConfig(A.class, B.class); WebappContext ctx = new WebappContext() {}; ctx.addContextInitParameter("contextConfigLocation", "classpath:applicationContext.xml"); ctx.addListener("com.package.something.AServletContextListener"); server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc); ctx.deploy(server); } } 

如果您注意到我正在使用@Before但是,if条件将使其作为@BeforeClass运行。 不要完全记住为什么我没有使用@BeforeClass ,我的猜测可能是由于if块中的一些配置。 无论如何,如果你好奇,试一试。

  1. 使用将要测试的资源创建ResourceConfig,这包括您的资源/控制器,ExceptionMapper(如果有),任何其他应该加载的类。
  2. 创建一个WebappContext实例,然后以编程方式向其添加所有web.xml上下文init参数,例如applicationContextapplicationContext包含基于spring的配置。
  3. 如果您的web.xml中有一个监听器,那么您需要以编程方式添加它们,如上所示
  4. 如果您有任何filter或其他东西,那么您需要以编程方式将它们添加到ctx
  5. 通过提供URI和ResourceConfig实例,使用Grizzly实例初始化server
  6. 您已经以编程方式创建了一个WebappContext ,它只是web.xml,现在使用它的deploy方法将服务器实例传递给它。 这将运行WebappContext配置并将其部署到server实例。

现在,您有一个测试运行Grizzly实例,其中包含应用于实例的web.xml和特定于Spring的配置。

@AfterClass看起来如下

 @AfterClass public static void tearDown() throws Exception { System.out.println("tearDown called ..."); if (server != null && server.isStarted()) { System.out.println("Shutting down the initialized Grizzly instance"); server.shutdownNow(); } } 

并使用REST保证框架进行示例测试

 @Test public void testGetAllOrderrs() { List orders= (List) when(). get("/orders"). then(). statusCode(200). extract(). response().body().as(List.class); assertThat(orders.size()).isGreaterThan(0); } 

上面的原因在没有指定基本路径的情况下工作是因为我将REST保证的基本路径设置如下

 RestAssured.baseURI = "http://localhost:8989/"; 

如果您不想使用REST保证那么

 @Test public void testGetAllOrders() { Client client = ClientBuilder.newBuilder().newClient(); WebTarget target = client.target(BASE_URI); Response response = target .path("/orders") .request(MediaType.APPLICATION_JSON) .get(); assertThat(response.getStatus()).isEqualTo(200); JSONArray result = new JSONArray(response.readEntity(String.class)); assertThat(result.length()).isGreaterThan(0); } 

泽西岛import

 import org.glassfish.grizzly.http.server.HttpServer; import org.glassfish.grizzly.servlet.WebappContext; import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; import org.glassfish.jersey.server.ResourceConfig;