Home > OS >  Test @EventListener with custom events Spring Kotlin
Test @EventListener with custom events Spring Kotlin

Time:03-14

I have created a set of custom events for my application

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)
}

I have a service that has a method for listening my custom events

@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)
    }
  }

The interesting point is that IntellIj annotates with the eventlistener icon next to the method defintion. When clicking on it I get redirected to all my invocations of publisher.publishEvent(myBigEvent) or publisher.publishEvent(myIntermediateEvent)

The issue is when I try to test it. I have the following setup

@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)
  }
}

I get 'Wanted but not invoked' ... 'Actually, there were zero interactions with this mock.' I think my issue is with the ApplicationEventPublisher that is not sending the events to my MailService under this test context ?

CodePudding user response:

Remove @TestExecutionListeners, since the default listeners should suffice.

If you're using Spring Boot, you should use @MockBean instead of @Mock.

In any case, you have to actually instruct JUnit to use Spring's testing support.

I assume that you are using JUnit 4, since I see @BeforeClass in the example. So I'm basing the following on that assumption (and using Java syntax instead of Kotlin).

You can instruct JUnit 4 to use Spring's testing support via @RunWith(SpringRunner.class). Note, however, that you'll also need to specify where your ApplicationContext configuration is.

For Spring Framework, you can do that with @ContextConfiguration. For Spring Boot, you'll likely want to use @SpringBootTest. Consult the documentation for testing support in Spring Framework and Spring Boot for details.

As a side note, you can also test ApplicationEvent publication without using a mock by using Spring Framework's built-in testing support for application events.

  • Related