如何测试Java EE7 Websocket

时间:2016-04-23 17:45:34

标签: java java-ee-7 tomee java-websocket tomee-7

我使用Java EE 7提供的api实现了一个WebSocket。此外,我已经实现了一个请求我的WebSocket没有任何问题的客户端。为了确保在执行某些代码更改时这仍然有效,我想实现也可以在构建服务器上运行的测试,例如,詹金斯CI不仅在当地。我正在使用maven。

这是我的服务器端点:

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+"!");
    }
}

这是我的客户端点:

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;
    }
}

我还有一些在使用CDI的构建服务器上测试的其他类。为了能够使用CDI和其他应用程序容器功能,我在版本EJBContainerRunner中使用带有apache TomeEE / OpenEJB的7.0.0-M3启动嵌入式TomEE运行我的测试并在之后将其关闭。使用这种方法,我没有要拨打的URL。这适用于例如JAX-RS REST服务,您可以在测试中调用类方法并检查响应。但是你如何用WebSockets做这样的事情呢?由于缺少Session,我无法简单地调用这些方法。

我目前的测试如下:

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");
    }

}

这可以在我的本地计算机上运行TomEE,例如: tomee-maven-plugin。但是这种方法不能在构建服务器上完成。有没有比配置特殊端口或设置虚拟机进行测试更简单的方法?

提前致谢!

1 个答案:

答案 0 :(得分:6)

我找到了一个解决我的测试问题的解决方案,没有使用vm,...

进行模拟

要向客户端发送应答消息,则无需呼叫session.getBasicRemote().sendText("...");。而是返回您要发送的邮件。

班级handleMessage中的WebSocket方法更改为:

@OnMessage
public String handleMessage(String message){
    return "Hello "+message+"!";
}

测试简化为:

@RunWith(EJBContainerRunner.class)
public class TestWebsocket {

    @Inject
    private WebSocket socket;

    @Test
    public void test() throws SocketException {
        String answer = socket.handleMessage("Java");
        assertThat(answer, is(equalTo("Hello Java!")));
    }   
}

此方法不会将消息发送到为测试启动的Web应用程序容器的外部。这使得处理测试变得更加容易。