首页 > 解决方案 > Spring WebSocket 集成测试随机工作

问题描述

我有一个非常简单的 SpringBoot 项目,它具有简单的配置和简单的集成测试来测试 WebSockets。

pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>sandbox.websocket</groupId>
    <artifactId>websocket</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

SpringBoot应用程序:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

消息代理配置

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/greeting")
                .withSockJS();
    }
}

集成测试以简单地连接到服务器、订阅消息代理并发送消息。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class WebSocketIntegrationTest {

    @LocalServerPort
    private int localServerPort;

    private BlockingQueue<String> blockingQueue;

    @Before
    public void setup() {
        blockingQueue = new LinkedBlockingDeque<>();
    }

    @Test
    public void shouldReceiveAMessageFromTheServer() throws Exception {
        String uri = "ws://localhost:" + localServerPort + "/greeting";

        WebSocketStompClient stompClient = new WebSocketStompClient(
                new SockJsClient(Collections.singletonList(
                        new WebSocketTransport(
                                new StandardWebSocketClient()))));

        String message = "MESSAGE TEST";

        ListenableFuture<StompSession> connect = stompClient.connect(uri, new StompSessionHandlerAdapter() {});
        StompSession session = connect.get(1, SECONDS);

        session.subscribe("/topic", new DefaultStompFrameHandler());
        session.send("/topic", message.getBytes());

        Assert.assertEquals(message, blockingQueue.poll(10, SECONDS));
    }

    class DefaultStompFrameHandler implements StompFrameHandler {

        @Override
        public Type getPayloadType(StompHeaders stompHeaders) {
            return byte[].class;
        }

        @Override
        public void handleFrame(StompHeaders stompHeaders, Object o) {
            System.out.println("=============================================================");
            System.out.println(new String((byte[]) o));
            System.out.println("=============================================================");
            blockingQueue.offer(new String((byte[]) o));
        }
    }
}

如果我从 javascript 客户端运行它并对其进行测试,它就像一个魅力。如果我运行集成测试,它只会在某些时候起作用。问题是有时 DefaultStompFrameHandler.handleFrame() 方法没有被调用,因此没有任何东西保存到队列中并且断言失败。

我编写了一个 InboundChannel 拦截器来拦截帧并将命令打印到控制台,并且所有四个命令都被打印(CONNECT、SUBSCRIBE、SEND、DISCONNECT)。

因此,包括 SEND 在内的所有命令都会发送到服务器,但有时(60-70%)无论 queue.poll 超时设置多长时间,都不会使用 StompFrameHandler。

请问有什么帮助吗?

标签: javaspringspring-websocket

解决方案


推荐阅读