How to test Spring @EventListener method?

In case, spinning up the whole Spring context is not an option, with Spring Boot 2.0.0 ApplicationContextRunner was introduced.

ApplicationContextRunner can create an application context in your test, allowing for more control over the context.

A complete test example could be:

package net.andreaskluth.context.sample;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

public class SimpleEventTest {

  private final ApplicationContextRunner runner = new ApplicationContextRunner();

  @Test
  public void happyPathSuccess() {
    AtomicBoolean sideEffectCausedByEvent = new AtomicBoolean(false);
    ObservableEffect effect = () -> sideEffectCausedByEvent.set(true);

    runner
        .withBean(SomeEventListener.class, effect)
        .run(
            context -> {
              context.publishEvent(new SomeEvent());
              assertThat(sideEffectCausedByEvent.get()).isTrue();
            });
  }

  public interface ObservableEffect {
    void effect();
  }

  @Component
  public static class SomeEventListener {

    private final ObservableEffect effect;

    public SomeEventListener(ObservableEffect effect) {
      this.effect = effect;
    }

    @EventListener(SomeEvent.class)
    public void listen() {
      effect.effect();
    }
  }

  public static class SomeEvent {}
}


First, As you're using Spring Boot, the testing of these becomes pretty straightforward. This test will spin up the boot context and inject a real instance of ApplicationEventPublisher, but create a mocked instance of SomeDependency. The test publishes the desired event, and verifies that your mock was invoked as you expected.

@RunWith(SpringRunner.class)
@SpringBootTest
public class EventPublisherTest {

   @Autowired 
   private final ApplicationEventPublisher publisher;

   @MockBean
   private SomeDependency someDependency;

   @Test
   public void test() {
      publisher.publishEvent(new MyApplicationEvent(createMySource()));

      // verify that your method in you 
      verify(someDependency, times(1)).someMethod();
   }
}