【问题标题】:How to test a component with websocket scope?如何使用 websocket 范围测试组件?
【发布时间】:2019-04-25 18:37:02
【问题描述】:

我正在尝试对标有 websocket 范围的简单组件进行简单测试。问题是我收到此错误:

Scope 'websocket' is not active for the current thread;

这很有意义,因为我使用模拟的 WebSocket 客户端执行登录,并且在 Spring 应用程序的客户端上下文中,客户端创建的 websocket 会话没有影响。

测试 websocket 范围组件的正确方法是什么?

组件类:

@Service
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class TrackerService {

    private final ConcurrentMap<String, Collection<Geolocation>> vehicleBeingTracked = new ConcurrentHashMap<>();

    public void startTracking(String plateSequence) {
        vehiclesBeingTracked.put(plateSequence, new ArrayList<>());
    }

    public void stopTracking(String plateSequence) {
        vehiclesBeingTracked.remove(plateSequence);
    }

    public void spotVehicle(String plateSequence, Geolocation geo) {
        vehiclesBeingTracked.get(plateSequence).add(geo);
    }

    public boolean isBeingTracked(String plateSequence) {
        return vehiclesBeingTracked.containsKey(plateSequence);
    }

}

控制器类:

@Controller
@MessageMapping("/operational/tracker")
public class TrackerController {

    @Autowired
    private TrackerService trackerService;

    @MessageMapping("/plate/{plateSequence}/track.start")
    public void startTracking(@DestinationVariable("plateSequence") String plateSequence) {
        trackerService.startTracking(plateSequence);
    }

}

测试类:

@RunWith(SpringRunner.class)
@ContextConfiguration
@SpringBootTest(classes = UnifyApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ActiveProfiles("test")
public class TrackerTest {

    @Autowired
    private TrackerService trackerService;

    @Test
    public void startTracking() {
        TrackerClient client = new TrackerClient("ws://localhost:9050/operational/websocket", "admin", "admin");
        client.connectAndWait();
        client.send("/operational/tracker/plate/ABC1234/track.start");
        TimeUnit.SECONDS.sleep(1);

        boolean result = trackerService.isBeingTracked("ABC1234"); // Here is the error
        Assert.assertTrue(result);
    }


}

【问题讨论】:

  • 请给我们看一下你的代码。您是否创建了使用 AbstractWebSocketMessageBrokerConfigurer 扩展配置的 websocket?您使用的是哪个客户端?如果您使用 stomp,则有一个名为 WebSocketStompClient 的内置客户端
  • 是的,实际上系统运行良好。我使用的是单例范围和一些静态引用。现在我正在重构代码以使用 websocket 范围,但我被困在这种测试上。
  • 当然它会失败,因为测试不在网络套接字范围内运行。它只能从您的测试用例不是的活动 Web 套接字连接内部获得。所以你需要找到一种不同的测试方式。您可能想要使用模拟而不是实际的作用域对象,而不是 @Autowired 使用 @MockBean
  • 但是无论如何都需要测试 websocket 范围的服务。那么,怎么可能做到呢?有没有办法在测试线程中获取会话上下文?

标签: java spring spring-boot spring-test spring-websocket


【解决方案1】:

尝试在测试类中使用以下代码来窥探 trackerService 服务:

@SpyBean
private TrackerService trackerService;

@Test
public void startTracking() {
    TrackerClient client = new 

    TrackerClient("ws://localhost:9050/operational/websocket", "admin", "admin");
    client.connectAndWait();
    client.send("/operational/tracker/plate/ABC1234/track.start");
    TimeUnit.SECONDS.sleep(1);

    boolean result = Mockito.verify(trackerService).isBeingTracked("ABC1234");
    Assert.assertTrue(result);
}

更新答案:

@MockBean
private TrackerService trackerService;

@Test
public void startTracking() {

    Mockito.doAnswer((Answer<Object>) invocationOnMock -> {
        Object[] args = invocationOnMock.getArguments();
        assertEquals("ABC1234", invocationOnMock.getArgument(0));
        return null;

    }).when(sessionTracker).sessionDestroyed(Mockito.any());

    TrackerClient client = new 

    TrackerClient("ws://localhost:9050/operational/websocket", "admin", "admin");
    client.connectAndWait();
    client.send("/operational/tracker/plate/ABC1234/track.start");
    TimeUnit.SECONDS.sleep(1);
}

【讨论】:

  • 哦,很遗憾听到这个消息!这次你也可以尝试完全模拟服务。我会更新答案
  • 这是一个有效的替代方案,但在这种情况下,模拟服务仍然不会被测试。
  • 这是一个集成测试,用于测试您的 websocket 范围内的服务调用,要测试您的服务功能,您不需要集成测试。只需轻松编写单元测试而不带整个上下文
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-19
  • 2016-04-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多