9

我正在尝试模拟我的程序的各种运行测试,在一个方法中设置一个 Jetty 服务器@Before并在一个@After.

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

我的前后代码如下:

@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();
    }
}
4

6 回答 6

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();
于 2013-04-19T20:00:51.147 回答
2

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

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

在任何情况下,由于这仅用于测试目的,因此仅启动服务器@BeforeClass并关闭它@AfterClass可以防止整个服务器关闭 kerfuffle,但要注意在测试套件的同一端口上启动另一台服务器。

于 2012-08-03T14:08:08.773 回答
0

I handle this using a couple of things. First, after each test, make sure your server is shutdown, and join() on it. Either do this in @After or @AfterClass depending on what you are doing.

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

Next, before each test, make sure the port is available. I use the snippet available at Sockets: Discover port availability using Java

Then, the setup code becomes

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);
}

The little extra sleep at the end ensures that the port is available; because just checking that it is available might make the system not reuse it. Another option is to just set SO_REUSEADDR when you are opening the port after having checked it.

于 2013-03-06T06:54:42.703 回答
0

我的猜测是它发生了端口冲突。我们实际上是为我们的测试这样做的,令人惊讶的是,性能影响并没有那么糟糕。正如答案所示,我们首先在所有测试之前启动单个服务器,但我们必须切换到支持突变测试。依赖 Maven 的一个缺点是您必须在旁边启动它才能在 IDE 中运行单个测试。

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

于 2012-09-28T23:01:01.633 回答
-1

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

您可能需要考虑围绕整个测试套件启动和停止服务器。如果您使用 Maven 进行构建,您可以结合使用故障安全和 Jetty 插件来完成此操作。

于 2012-08-04T09:50:22.587 回答
-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

于 2012-08-03T11:31:17.397 回答