在JUnit测试之间启动和停止Jetty服务器

时间:2012-08-03 10:59:11

标签: java testing junit jersey jetty

我正在尝试模拟我的程序的各种运行测试,使用@Before方法设置Jetty服务器并在@After中关闭它。

我的第一个测试将成功运行,但在尝试在以下测试中发布数据com.sun.jersey.api.client.ClientHandlerException: java.net.SocketException: Software caused connection abort: recv failed时。有什么方法可以让我的服务器(和客户端?)在测试之间干净地关闭?

My Before and After代码如下:

@Before
public void startServer() {
    try {
        server = new Server(8080);
        ServletContextHandler root = new ServletContextHandler(server, "/ingest", ServletContextHandler.SESSIONS);

        root.addServlet(new Servlet(), "/*");

        server.start();

        client = new Client();
        client.setChunkedEncodingSize(16 * 1024);

        FileInputStream stream = new FileInputStream(testFile);
        try {
            client.resource(uri).type(MediaType.APPLICATION_OCTET_STREAM).post(stream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            Closeables.closeQuietly(stream);
            client.destroy();
        }
    } catch (Exception e) {
        e.printStackTrace();
        fail("Unexpected Exception when starting up server.");
    }
}

@After
public void shutDown() {
    if (output.exists()) {
        output.delete();
    }
    try {
        server.stop();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

6 个答案:

答案 0 :(得分:8)

测试方案的最佳做法是不对端口进行硬编码。这只会在其他地方运行时导致冲突,尤其是在负载量或项目种类繁多的CI系统上。

在Jetty 9中(6,7,8中的相同想法)

_server = new Server();
_connector = new ServerConnector(_server);  
_server.setConnectors(new Connector[] { _connector });
_server.start();
int port = _connector.getLocalPort();

答案 1 :(得分:2)

事实证明,我所拥有的实际上是在工作,但是由于server.stop()的异步性质,我的新服务器试图在前一个服务器的关闭线程完全执行之前进行实例化。

Thread.sleep(n)之后的简单server.stop()为服务器提供了在测试之间关闭所需的时间。不幸的是,服务器似乎过早声称它已经停止,从而通过检查服务器状态来阻止一个确切的解决方案 - 但也许在服务器上有一些东西需要轮询;可能检查线程池可以提供一致的结果吗?

在任何情况下,由于这仅用于测试目的,仅仅在@BeforeClass中启动服务器并在@AfterClass中关闭服务器会阻止整个服务器关闭kerfuffle,但要注意然后启动另一个服务器服务器位于测试套件的同一端口上。

答案 2 :(得分:0)

我的猜测是它发生了端口冲突。我们实际上是为我们的测试做到这一点,并且令人惊讶的是,性能受到的影我们首先在所有测试之前启动单个服务器,如答案所示,但我们不得不切换到支持突变测试。依赖Maven的一个缺点是你必须在侧面启动它才能在IDE中运行单个测试。

对于任何有兴趣的人,我们的实施都在这里:embedded-test-jetty。它在不同的端口上同时运行多个服务器(用于并行测试),检查端口可用性,支持SSL等。

答案 3 :(得分:0)

我使用了几件事来解决这个问题。首先,在每次测试之后,确保您的服务器已关闭,并且join()在其上。可以在@After@AfterClass中执行此操作,具体取决于您正在执行的操作。

server.stop();
server.join();

接下来,在每次测试之前,确保端口可用。我使用 Sockets: Discover port availability using Java

上提供的代码段

然后,设置代码变为

public static void waitForPort(int port) {
    while( !available(port) ) {
        try { Thread.sleep(PORT_SLEEP_MILLIS); } 
        catch (InterruptedException e) {}
    }
}

@Before
public void setUp() throws Exception {
    waitForPort(9876);
    waitForPort(9877);

    // Make sure the ports are clear
    Thread.sleep(500);
}

最后的小额外sleep确保端口可用;因为只检查它是否可用可能会使系统无法重复使用它。另一种选择是在检查后打开端口时设置SO_REUSEADDR

答案 4 :(得分:-1)

尝试:

server = new Server();
    SocketConnector connector = new SocketConnector();
    connector.setPort(8080);
    server.setConnectors(new Connector[] { connector });
    WebAppContext context = new WebAppContext();
    context.setServer(server);
    context.setContextPath("/your-context");
    context.setWar("path to war");
    server.addHandler(context);
    Thread monitor = new MonitorThread();
    monitor.start();
    server.start();
    server.join();

然后你说的地方:

    server.stop()

有用的文章:
http://www.codeproject.com/Articles/128145/Run-Jetty-Web-Server-Within-Your-Application

答案 5 :(得分:-1)

我意识到这并没有直接回答你的问题......但是当你有多个需要服务器的集成测试时,在@Before@After方法中启动和停止服务器效率很低正在运行,因为每次测试都会重新启动服务器。

您可能需要考虑在整套测试中启动和停止服务器。如果您使用Maven进行构建,则可以使用failafe和Jetty插件的组合来完成此操作。