2009-09-11 87 views
1

我已經實現了一個RMI服務器,現在我想測試使用JUnit測試來正確實施啓動和停止此服務器的方法。單元測試我的RMI服務器的停止方法時出現問題

這裏是我的RMI服務器(簡化)代碼:

public void startServer() { 
    try { 
     ... 
     registry = LocateRegistry.createRegistry(serverPort); 
     registry.rebind("foobar", myRemoteObject); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

public void stopServer() { 
    try { 
     registry.unbind("foobar"); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

現在,我想打一個JUnit測試,以檢查是否startServer()stopServer()工作正常。

因此,我實現了這個簡單的JUnit測試:

private boolean isRunning(int port) { 
    boolean portTaken = false; 
    ServerSocket socket = null; 
    try { 
     socket = new ServerSocket(port); 
     // If we have succesfully created the ServerSocket, then it means that the port is available... 
    } catch (IOException e) { 
     portTaken = true; 
     if (socket != null) { 
      try { 
       socket.close(); 
      } catch (IOException e2) { 
      } 
     } 
    } 
    return portTaken; 
} 

@Test 
public void testStartAndStopServer() { 
    MyRMIServer server = new MyRMIServer(); 
    assertNotNull(server); 
    int port = server.getServerPort(); 
    assertTrue(port != -1); 
    // Check if the current server is NOT running. 
    assertFalse(isRunning(port)); 
    // Start the server and then check if it is running. 
    server.startServer(); 
    assertTrue(isRunning(port)); 
    // Now stop the server... 
    server.stopServer(); 
    assertFalse(isRunning(port)); 
} 

我的問題是,最後斷言無效。如果我在方法isRunning()中打印堆棧跟蹤,我得到錯誤java.net.BindException: Address already in use: JVM_Bind

這意味着該端口仍在使用,所以我想我的stopServer()是不正確的。我錯了什麼?

需要注意的是,如果我之前打電話給我的方法stopServer()後使用registry.list()方法,我看到:

BEFORE: foobar 
AFTER: (nothing) 

編輯:

我也修改了我的stopServer()關於解決方案說明here

public void stopServer() { 
    try { 
     registry.unbind("foobar"); 
     UnicastRemoteObject.unexportObject(myRemoteObject, true); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

但它不能解決我的問題...

回答

0

首先,我會傾向於避免空的異常塊,即使在「不能發生」的情況下。

try { 
      socket.close(); 
    } catch (IOException e2) { 
    } 

只是同心地有一個例外。

我(相當狂野)的猜測是,你可能有時間問題。也許網絡基礎設施需要很短的時間才能注意到套接字已關閉。在最終斷言修復之前,睡一兩秒鐘?

+0

1.是的,在我的完整代碼中,沒有任何異常塊是空的;)這只是爲了簡化代碼。 2.我試圖在server.stopServer()之後放一個Thread.sleep(upTo5000ms);但它沒有幫助:( – romaintaz 2009-09-11 09:06:59

0

我想你需要導出註冊表。嘗試:

public void stopServer() { 
    try { 
     registry.unbind("foobar"); 
     UnicastRemoteObject.unexportObject(registry, true); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

然而,one source要求你不能,直到退出JVM釋放的端口。我不知道這是否正確(還沒有嘗試過),但未登錄註冊表是朝着正確方向邁出的一步。

1

我有同樣的問題,並最終改變我的服務器代碼,以便啓動方法將基本上看起來像(注意捕捉後調用getRegistryrebind將回到註冊表,如果它已經在那裏) :

public void startServer() { 
    try { 
     ... 
     registry = LocateRegistry.createRegistry(serverPort); 
    } catch (RemoteException e) { 
    } 
    LocateRegistry.getRegistry(port); 
    registry.rebind("foobar", myRemoteObject); 
}