使用自定义事件测试 @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
发布而不使用模拟
我已经为我的应用程序创建了一组自定义事件
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
发布而不使用模拟