Skip to content
Kona

Testing events

Two approaches cover most cases:

  1. Unit-test a listener against a real EventDispatcher (or call handle directly).
  2. Record what your code dispatched with org.konaframework.testing.FakeEvent.

Broader testing setup lives under Testing and Database & fakes.

FakeEvent wraps an EventDispatcher and records every object passed to its own dispatch method. Listeners registered on fake.dispatcher still run when you call fake.dispatch.

API Role
dispatcher Underlying EventDispatcher — register listeners here
dispatch(Any) Append to the recording list, then call dispatcher.dispatch
events(): List<Any> Snapshot of recorded payloads (copy)
assertDispatched(Class<*>): Boolean true if any recorded event is an instance of that class
clear() Clear recordings and dispatcher.flush()

assertDispatched uses Class.isInstance, so it matches subclasses of the type you pass. The real bus’s listener matching remains exact-class only; this assertion is only about the recording list.

import org.konaframework.testing.FakeEvent
data class OrderPlaced(val id: String)
val events = FakeEvent()
var heard = false
events.dispatcher.listen(OrderPlaced::class.java) { heard = true }
events.dispatch(OrderPlaced("o1"))
assert(heard)
assert(events.assertDispatched(OrderPlaced::class.java))
assertEquals(1, events.events().size)
events.clear()
assert(events.events().isEmpty())
assert(!events.dispatcher.hasListeners(OrderPlaced::class.java))
import org.konaframework.testing.FakeEvent;
FakeEvent events = new FakeEvent();
events.dispatcher.listen(OrderPlaced.class, event -> { /* … */ });
events.dispatch(new OrderPlaced("o1"));
assertTrue(events.assertDispatched(OrderPlaced.class));
assertEquals(1, events.events().size());
events.clear();

FakeEvent.dispatch records payloads. Production code that resolves EventDispatcher and calls dispatch on that instance does not go through FakeEvent.dispatch, so assertDispatched stays empty unless the test itself publishes via fake.dispatch.

Prefer registering a capturing listener on the same bus the app uses:

val bus = app.resolve(EventDispatcher::class.java)
val seen = mutableListOf<Any>()
bus.listen(OrderPlaced::class.java) { seen += it }
app.resolve(CheckoutService::class.java).placeOrder(/* … */)
assertEquals(listOf(OrderPlaced("o1")), seen)

Or inject a fresh EventDispatcher into the unit under test:

val bus = EventDispatcher()
val seen = mutableListOf<Any>()
bus.listen(OrderPlaced::class.java) { seen += it }
val service = CheckoutService(bus)
service.placeOrder(/* … */)
assertEquals(listOf(OrderPlaced("o1")), seen)

Use FakeEvent when the test (or a harness) is the publisher and you want a recording list plus optional listeners:

val fake = FakeEvent()
fake.dispatcher.listen(OrderPlaced::class.java) { /* side effect under test */ }
fake.dispatch(OrderPlaced("o1"))
assertTrue(fake.assertDispatched(OrderPlaced::class.java))

Call handle without the bus:

val listener = SendWelcomeEmail(mailer)
listener.handle(UserRegistered(1, "a@b.c"))
assertEquals(1, mailer.sentCount)
val bus = EventDispatcher()
val order = mutableListOf<String>()
bus.listen(Ping::class.java) { order += "a" }
bus.listen(Ping::class.java) { order += "b" }
bus.dispatch(Ping())
assertEquals(listOf("a", "b"), order)
Expectation Reality
Queue the event Still synchronous — same as EventDispatcher
Fake Cadence model events Use ModelDispatcher.flush() / withoutEvents — see Cadence events
Assert listener count after production dispatch Use dispatcher.listenerCount / hasListeners, or capture in listeners
Replace a global Event::fake() facade Not shipped — construct FakeEvent in the test

Dependency: org.konaframework:kona-testing (pulls in kona-events).