【问题标题】:Problem when unit-testing the stop method of my RMI Server对我的 RMI 服务器的停止方法进行单元测试时出现问题
【发布时间】:2009-09-11 08:30:35
【问题描述】:

我已经实现了一个 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() 不正确。我做错了什么?

请注意,如果我在调用我的方法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();
    }
}

但这并不能解决我的问题...

【问题讨论】:

    标签: java junit rmi


    【解决方案1】:

    我遇到了同样的问题,最后修改了我的服务器代码,以便启动方法基本上看起来像(注意对 getRegistryrebind 的调用之后会返回注册表(如果它已经存在):

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

    【讨论】:

      【解决方案2】:

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

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

      只是令人难以置信的是那里有一个例外。

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

      【讨论】:

      • 1.是的,在我的完整代码中,没有异常块是空的;)这里只是为了简化代码。 2. 我试图在 server.stopServer(); 之后放置一个 Thread.sleep(upTo5000ms),但它没有帮助:(
      【解决方案3】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-25
        • 2011-07-07
        • 2016-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-04
        • 2023-03-16
        相关资源
        最近更新 更多