【问题标题】:@WebMvcTest vs @ContextConfiguration when testing WebSocket controllers测试 WebSocket 控制器时的 @WebMvcTest 与 @ContextConfiguration
【发布时间】:2021-06-24 18:41:02
【问题描述】:

我目前正在使用 WebSockets 的 Spring Boot 项目中为我的控制器编写测试。 由于很难获得有关该主题的信息,我唯一的线索是docs 推荐的this example。 请允许我尝试解释我到目前为止的尝试,尝试理解并设置我的测试环境。我遵循基于上下文的方法,我在@WebMvcTest@ContextConfiguration(示例使用)之间纠结。 我使用 @WebMvcTest 的动机完全是 Spring Boot docs 中的这一行:

在测试 Spring Boot 应用程序时,通常不需要 [使用 @ContextConfiguration(classes=…​) 来指定要加载哪个 Spring @Configuration,或在测试中使用嵌套的 @Configuration 类]。只要您没有明确定义,Spring Boot 的 @*Test 注释就会自动搜索您的主要配置。

@WebMvcTest 因此似乎特别适合这项任务,因为它只关注 web 层 limiting the set of scanned beans 只关注那些必要的(例如@controller),而不是旋转完整的ApplicationContext

我下面的代码示例使用字段注入来初始化通道拦截器以捕获通过它们发送的消息。

@Autowired private AbstractSubscribableChannel clientInboundChannel;
@Autowired private AbstractSubscribableChannel clientOutboundChannel;
@Autowired private AbstractSubscribableChannel brokerChannel;

据我所知,这些字段使得示例中必须存在 TestConfig 类(请参阅末尾的代码块以获取完整的类定义),因为没有它,我会收到一个错误说不bean 有资格成为 autowire 候选人。我相信TestConfig中的这两个字段是关键:

@Autowired
private List<SubscribableChannel> channels;
@Autowired
private List<MessageHandler> handlers;

但是,如果没有@ContextConfiguration(classes = [WebSocketConfig::class]) WebSocketConfig 是我自己的 WebSocket 配置文件),这两个字段总是null 导致错误。 到目前为止,这意味着需要 @ContextConfiguration(classes = [WebSocketConfig::class])TestConfig 的存在。

有趣的是,如果没有 @WebMvcTestclientInboundChannelclientOutboundChannelbrokerChannel,则永远不会真正初始化。所以这留给我的是我需要@WebMvcTest @ContextConfiguration,这在某种程度上看起来很奇怪。 由于示例 repo 的最后一次更新已有两年多的历史,我无法摆脱它可能有些过时的感觉。

这就是我的测试类(Kotlin)目前的样子。为简洁起见,我省略了 createRoom 测试用例:

@WebMvcTest(controllers = [RoomController::class])
@ContextConfiguration(classes = [WebSocketConfig::class, RoomControllerTests.TestConfig::class])
class RoomControllerTests {
    @Autowired
    private lateinit var clientInboundChannel: AbstractSubscribableChannel

    @Autowired
    private lateinit var clientOutboundChannel: AbstractSubscribableChannel

    @Autowired
    private lateinit var brokerChannel: AbstractSubscribableChannel

    private lateinit var clientOutboundChannelInterceptor: TestChannelInterceptor

    private lateinit var brokerChannelInterceptor: TestChannelInterceptor

    private lateinit var sessionId: String

    @BeforeEach
    fun setUp() {
        brokerChannelInterceptor = TestChannelInterceptor()
        clientOutboundChannelInterceptor = TestChannelInterceptor()
        brokerChannel.addInterceptor(brokerChannelInterceptor)
        clientOutboundChannel.addInterceptor(clientOutboundChannelInterceptor)
    }

    @Test
    fun createRoom() {
        // test room creation
        // ...
    }

    @Configuration
    internal class TestConfig : ApplicationListener<ContextRefreshedEvent?> {
        @Autowired
        private val channels: List<SubscribableChannel>? = null

        @Autowired
        private val handlers: List<MessageHandler>? = null

        override fun onApplicationEvent(event: ContextRefreshedEvent) {
            for (handler in handlers!!) {
                if (handler is SimpAnnotationMethodMessageHandler) {
                    continue
                }
                for (channel in channels!!) {
                    channel.unsubscribe(handler)
                }
            }
        }
    }
}

【问题讨论】:

    标签: spring spring-boot controller integration-testing spring-websocket


    【解决方案1】:

    here 发布的答案是我开始了解如何使用 @WebMvcTest@ContextConfiguration 的第一条线索。 看起来真正需要的行是@ContextConfiguration(classes = [WebSocketConfig::class]),因为没有它,就找不到必要的配置(在这种情况下是我自己的WebSocketConfig)。

    虽然@WebMvcTest(和一般的测试切片)对主要配置执行automatically search,但主应用程序类定义的配置是找到的配置,因为该类是用@SpringBootApplication注释的配置。

    此外,@WebMvcTest 之类的测试切片会从扫描中清除 exclude @configuration 类,这意味着它们不会包含在测试切片加载的应用程序上下文中。 支持这一点的事实是,如果 @WebMvcTest 被替换为 @SpringBootTest(即使没有 @ContextConfiguration(classes = [WebSocketConfig::class])),测试也可以正常工作——这意味着 WebSocketConfig 已加载。

    总而言之,在我看来,有 3 种方法可以在应用程序上下文中包含非主配置,使其成为 detected in integration tests

    • 使用 @SpringBootTest 注释测试类(以及可选的 @ContextConfiguration 以将加载的 bean 数量限制为仅需要的数量)
    • 使用测试切片(例如@WebMvcTest)和@ContextConfiguration 一起注释测试类
    • 用测试片(例如@WebMvcTest)注释测试类并在主类中定义配置(即用@SpringBootApplication注释的那个)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      相关资源
      最近更新 更多