Unit testing event listeners?

Does anyone have any recommendations on properly unit testing an EventListenerProvider implementation? I suppose this would actually be more functional/integration testing, as it would ideally involve bringing up a Keycloak instance, installing/activating the listener, and performing some actions, and then validating that an event had been received by the listener.

I’ve been thinking about either using the org.keycloak.testsuite.KeycloakServer in junit or the testcontainers approach. I wanted to see if anyone here had a recommendation or template.

Thank you!

You already know my testcontainers-keycloak project?

1 Like

I didn’t know about it. This is awesome. Thank you @dasniko !

1 Like

Also, I tried another approach that uses the org.keycloak.testsuite.KeycloakServer. The downside is that because keycloak-testsuite-utils isn’t in Maven Central, you have to build it yourself in order to use this method. The upside is that it works with JUnit4, which I had the requirement of sticking to. This also ran much faster than the testcontainers approach, but is less flexible in features, control, and similarity to an actual production environment.

This is how to use it in JUnit4:

  @ClassRule public static KeycloakSuite server = KeycloakSuite.SERVER;

  @BeforeClass
  public static void commonSetup() {
    Keycloak keycloak = server.client();
    //do setup here that is common to all tests in this class
  }

  @Test
  public void exampleTest() {
    Keycloak keycloak = server.client();
    RealmRepresentation realm = keycloak.realm("master").toRepresentation();
    assertThat(realm.getId(), is("master"));
  }

Full code here:

You can also do JUnit tests with mocks (e.g. Mockito)


@ExtendWith(MockitoExtension.class)
@TestMethodOrder(OrderAnnotation.class)
final class HUGListenerTests extends AbstractTests {

	@Mock(answer = Answers.RETURNS_DEEP_STUBS)
	private Event event;

	@Mock(answer = Answers.RETURNS_DEEP_STUBS)
	KeycloakSession session;

	@InjectMocks
	@Spy
	private HUGListener listener = new HUGListener(session);

	@Captor
	private ArgumentCaptor<String> stringCaptor;

	@BeforeAll
	private static void beforeAll() throws Exception {
	}

	@AfterAll
	private static void afterAll() throws IOException {
	}

	HUGListenerTests() throws Exception {
		logger = Logger.getLogger(HUGListenerTests.class);
	}

	@Test
	@DisplayName("Supported event KO")
	@Order(1)
	void onSupportedEvent_KO(TestInfo testInfo) throws Exception {
		logInfos(testInfo);

		when(event.getType()).thenReturn(EventType.RESTART_AUTHENTICATION);

		listener.onEvent(event);

		verify(listener, times(1)).onNotSupportedEvent(event);

		logSep();
	}

	@Test
	@DisplayName("Login event OK")
	@Order(2)
	void onLoginEvent_OK(TestInfo testInfo) throws Exception {
		logInfos(testInfo);

		when(event.getType()).thenReturn((EventType) HUGListener.USER_EVENT_TYPES_4_LOGIN_HISTORY.toArray()[0]);
		when(event.getRealmId()).thenReturn("realmId");
		when(event.getUserId()).thenReturn("userId");
		RealmModel realm = session.realms().getRealm(event.getRealmId());
		UserModel user = session.users().getUserById(event.getUserId(), realm);
		when(user.getId()).thenReturn("userId");
		when(user.getAttribute(UserUtil.USER_ATTR_LOGIN_HISTORY)).thenReturn(List.of(LoginHistory.testDataAsJson()));

		listener.onEvent(event);

		verify(listener, times(1)).onLoginEvent(event, user);

		logSep();
	}
1 Like