Ich habe einen WebSocket mit der API Java EE 7 implementiert. Zusätzlich habe ich einen Client implementiert, der meinen WebSocket ohne Probleme anfordert. Um sicherzugehen, dass dies funktioniert, wenn einige Codeänderungen durchgeführt werden, möchte ich Tests implementieren, die auch auf einem Build-Server wie z. Jenkins CI und nicht nur lokal. Ich benutze Maven.Wie man einen Java EE7 Websocket testet
Hier ist mein Server-Endpunkt:
import javax.enterprise.context.ApplicationScoped;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@ApplicationScoped
@ServerEndpoint("/example")
public class WebSocket {
private final Set<Session> sessions = Collections.synchronizedSet(new HashSet<>());
@OnOpen
public void open(Session session) {
sessions.add(session);
}
@OnClose
public void close(Session session) {
sessions.remove(session);
}
@OnError
public void onError(Throwable error) {
//TODO do something
}
@OnMessage
public void handleMessage(String message, Session session) throws IOException {
session.getBasicRemote().sendText("Hello "+message+"!");
}
}
Hier ist mein Client-Endpunkt:
import javax.websocket.*;
import java.io.IOException;
import java.net.URI;
@ClientEndpoint
public class WebsocketClient {
private String uri = "ws://localhost:8181/<some-path>/example";
private Session userSession = null;
private String answer;
public WebsocketClient() {
try {
WebSocketContainer container = ContainerProvider
.getWebSocketContainer();
container.connectToServer(this, new URI(uri));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean isClosed() {
return userSession == null || !userSession.isOpen();
}
@OnOpen
public void onOpen(Session userSession) {
this.userSession = userSession;
}
@OnClose
public void onClose(Session userSession, CloseReason reason) {
this.userSession = null;
}
@OnMessage
public void onMessage(String message) {
this.answer = message;
}
public String getAnswer() {
return answer;
}
public void sendMessage(String message) {
if (userSession != null && userSession.isOpen())
try {
this.userSession.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
else {
System.out.println("Session closed!");
}
}
public void reset() {
this.answer = null;
}
}
ich auch einige andere Klassen, die auf dem Build-Server getestet werden, die CDI verwenden. Um die CDI- und andere Anwendungscontainer-Funktionalität nutzen zu können, verwende ich die EJBContainerRunner
mit Apache TomeEE/OpenEJB in der Version 7.0.0-M3
, die ein eingebettetes TomEE startet, führt meine Tests aus und beendet sie anschließend. Mit diesem Ansatz habe ich keine URL zum Anrufen. Dies funktioniert z.B. JAX-RS REST-Dienste, bei denen Sie einfach Ihre Klassenmethoden in Ihren Tests aufrufen und die Antworten prüfen können. Aber wie macht man so etwas mit WebSockets? Ich kann die Methoden wegen der fehlenden Session
nicht einfach anrufen.
Mein aktueller Test sieht wie folgt aus:
import org.apache.openejb.junit.jee.EJBContainerRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.SocketException;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
@RunWith(EJBContainerRunner.class)
public class TestWebsocket {
private WebsocketClient socket;
@Test
public void test() throws SocketException {
String answer = requestSynchronous("Java");
assertThat(answer, is(equalTo("Hello Java!")));
}
public String requestSynchronous(String message) throws SocketException {
if (socket == null || socket.isClosed()) {
socket = new WebsocketClient();
}
socket.reset();
socket.sendMessage(message);
String answer = null;
int i = 0;
while (answer == null && i < 10000) {
try {
answer = socket.getAnswer();
Thread.sleep(1);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (answer != null)
return answer;
else throw new SocketException("Connection timeout");
}
}
Dies funktioniert eine TomEE auf meinem lokalen Rechner läuft mit z.B. die tomee-maven-plugin
. Dieser Ansatz kann jedoch nicht auf dem Build-Server durchgeführt werden. Gibt es einen einfacheren Weg als spezielle Ports zu konfigurieren oder eine virtuelle Maschine zum Testen einzurichten?
Vielen Dank im Voraus!