2012-08-03 61 views
6

我試圖模擬我的程序的各種運行測試,在@Before方法中設置Jetty服務器並在@After中關閉它。在JUnit測試之間啓動和停止Jetty服務器

我的第一個測試會成功運行,但是在嘗試POST數據後,發生以下測試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(); 
    } 
} 

回答

8

測試場景中的最佳做法是不要硬編碼端口。這隻會導致在其他地方運行時發生衝突,特別是在負載適中或各種項目的CI系統上。

在碼頭9

(6同樣的想法,7,8)

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

真棒,這對我很有用! – hsestupin 2013-04-29 00:10:03

+0

對於Jetty 6,我必須使用SelectChannelConnector(ServerConnector不存在)。 – Dennie 2014-01-16 13:55:07

-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

2

事實證明,我的工作實際上是在工作,但是由於server.stop()的異步性質,我的新服務器試圖在前一個服務器的關閉線程完全執行之前實例化。

server.stop()之後的簡單Thread.sleep(n)爲服務器提供了兩次測試之間需要關閉的時間。不幸的是,服務器似乎過早地聲稱它已經停止,從而通過檢查服務器狀態來阻止確切的解決方案 - 但也許有些事情需要在服務器上進行輪詢;可能檢查線程池可能會提供一致的結果?

在任何情況下,因爲這只是用於測試目的,僅僅是啓動服務器在@BeforeClass和關閉它在@AfterClass防止整個服務器關閉亂哄哄,但隨後開始另一臺服務器在同一端口上當心測試套件。

+0

你可能只是想用'server.join()'等待它停止。 – 2013-03-06 06:55:42

-1

我意識到這並不直接回答你的問題......但是當你有多個需要服務器運行的集成測試時,啓動和停止服務器的方法效率不高,因爲服務器每次測試都會重新啓動。

您可能需要考慮在整套測試中啓動和停止服務器。如果您正在使用Maven構建版本,則可以使用故障安全和Jetty插件的組合執行此操作。

+0

有關使用Jetty with Failsafe的示例,請參閱http://maven.apache.org/plugins/maven-failsafe-plugin/usage.html。 – Kkkev 2012-08-13 22:16:15

0

我的猜測是它得到一個端口衝突。我們實際上是爲我們的測試做到這一點,令人驚訝的是,性能並沒有那麼糟糕。我們首先在所有測試之前啓動一臺服務器,正如答案所示,但我們必須切換到支持變異測試。依賴Maven的一個缺點是你必須啓動它才能在IDE中運行單個測試。

對於任何有興趣的人,我們的實施在這裏:embedded-test-jetty。它在不同的端口上一次運行多個服務器(用於並行測試),檢查端口可用性,支持SSL等。

+1

imho,在詢問是否有人對代碼解決方案感興趣,如果你認爲它是相關的,只是提出來,不要問:)沒有意義。如果時間太長,可以將鏈接放到回購站。 – 2012-09-29 04:17:41

+0

不知道什麼時候我們會把它從我們的內部回購中移出 - 但它現在在那裏:) – 2012-10-07 21:42:44

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