使用自定义事件测试 @EventListener Spring Kotlin

Test @EventListener with custom events Spring Kotlin

我已经为我的应用程序创建了一组自定义事件

sealed class myEvent(open val id: Int) {
  data class myBigEvent(override val id : Int) : myEvent(id)
  data class myIntermediateEvent(override val id: Int): myEvent(id)
}

我有一个服务可以监听我的自定义事件

@Service
class MailService(
  private val otherService: OtherService
) {

  @EventListener(myEvent.myBigEvent::class, myEvent.myIntermediateEvent::class)
  @Async
  fun handleProcessEvent(event: myEvent) {
    if (event.id != 10 && otherService.hasCompleted) {
      sendMail(event)
    }
  }

有趣的一点是,IntellIj 在方法定义旁边使用事件监听器图标进行注释。单击它时,我会被重定向到我对 publisher.publishEvent(myBigEvent)publisher.publishEvent(myIntermediateEvent)

的所有调用

问题出在我尝试测试它时。我有以下设置

@TestExecutionListeners
class myEventTest {

  @Autowired
  private lateinit var publisher: ApplicationEventPublisher

  @Mock
  private lateinit var mailService: MailService

  @BeforeClass
  fun start() {
    publisher = ApplicationEventPublisher {}
    MockitoAnnotations.initMocks(this)
  }

  @Test
  fun `should receive cmlaProcessEvent published event`() {
    val cmlaProcessEvent = JobProcessEvent.CmlaProcessSimulationProcessEvent(mlaSimulationRun)
    this.publisher.publishEvent(cmlaProcessEvent)
    verify(mailService, times(1)).handleProcessEvent(cmlaProcessEvent)
  }
}

我得到 'Wanted but not invoked' ... 'Actually, there were zero interactions with this mock.' 我认为我的问题是 ApplicationEventPublisher 在此测试上下文中没有将事件发送到我的 MailService?

删除 @TestExecutionListeners,因为默认侦听器应该足够了。

如果您使用 Spring 启动,您应该使用 @MockBean 而不是 @Mock

无论如何,您必须实际指示 JUnit 使用 Spring 的测试支持。

我假设您使用的是 JUnit 4,因为我在示例中看到了 @BeforeClass。因此,我将以下内容基于该假设(并使用 Java 语法而不是 Kotlin)。

您可以通过 @RunWith(SpringRunner.class) 指示 JUnit 4 使用 Spring 的测试支持。但是请注意,您还需要指定 ApplicationContext 配置的位置。

对于 Spring 框架,您可以使用 @ContextConfiguration 来实现。对于 Spring 引导,您可能希望使用 @SpringBootTest。有关详细信息,请参阅 Spring Framework and Spring Boot 中的测试支持文档。

附带说明一下,您还可以通过使用 Spring 框架的 built-in testing support for application events.

来测试 ApplicationEvent 发布而不使用模拟