单元测试我的RMI服务器的stop方法时出现问题

时间:2009-09-11 08:30:36

标签: java junit rmi

我已经实现了RMI服务器,现在我想测试是否使用JUnit测试正确实现了启动和停止此服务器的方法。

以下是我的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()不正确。我出了什么问题?

请注意,如果我在调用方法registry.list()之前和之后使用stopServer()方法,我会看到:

BEFORE: foobar
AFTER: (nothing)

编辑:

我还修改了stopServer()关于解释here的解决方案:

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

但它并没有解决我的问题...

3 个答案:

答案 0 :(得分:1)

我遇到了同样的问题并最终修改了我的服务器代码,因此start方法基本上就是这样(在捕获之后注意调用getRegistryrebind 如果它已经存在,它将返回注册表:

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

答案 1 :(得分:0)

首先,我倾向于避免空的异常块,即使在“不可能发生”的情况下也是如此。

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

可以肯定的是那里有一个例外。

我(相当疯狂)的猜测是,你可能有时间问题。也许网络基础设施需要很短的时间才能注意到套接字已关闭。在最终断言修复之前,是否会睡一两秒?

答案 2 :(得分:0)

我认为您需要取消导出注册表。尝试:

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

但是,one source声称在JVM退出之前无法释放端口。我不知道这是不是真的(没有尝试过),但是取消注册表是朝着正确方向迈出的一步。