Проблема при модульном тестировании метода остановки моего сервера RMI - PullRequest
1 голос
/ 11 сентября 2009

Я реализовал сервер 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)
<Ч />

Edit:

Я также изменил свой stopServer() относительно решения, объясненного здесь :

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

но это не решает мою проблему ...

Ответы [ 3 ]

1 голос
/ 13 сентября 2009

У меня была та же проблема, и я закончил тем, что изменил свой серверный код так, чтобы метод start в основном выглядел так реестр, если он уже был там):

public void startServer() {
    try {
        ...
        registry = LocateRegistry.createRegistry(serverPort);
    } catch (RemoteException e) {
    }
    LocateRegistry.getRegistry(port);
    registry.rebind("foobar", myRemoteObject);  
}
0 голосов
/ 13 сентября 2009

Я думаю, вам нужно удалить реестр. Попробуйте:

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

Однако один источник утверждает, что вы не можете освободить порт, пока JVM не закроется. Я не знаю, правда это или нет (еще не пробовал), но отмена реестра - это шаг в правильном направлении.

0 голосов
/ 11 сентября 2009

Во-первых, я бы старался избегать пустых блоков исключений, даже в случаях "не может быть".

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

просто, конечно, есть исключение.

Мое (довольно дикое) предположение, что у вас может быть проблема с синхронизацией. Возможно, сетевой инфраструктуре требуется короткое время, чтобы заметить, что сокет закрыт. Сон на секунду или две до окончательного утверждения это исправить?

...