Skip to content

Commit

Permalink
Make in-memory appender classes part of the public API (#450)
Browse files Browse the repository at this point in the history
* Move InMemoryAppender, InMemoryAppenderAssertions, and
  InMemoryAppenderExtension to the production sources.
* Enhance the javadocs for these classes.
* Add new assertThatAppender entry point to
  InMemoryAppenderAssertions to avoid static import
  conflicts with AssertJ's Assertions#assertThat.
* Remove assertNumberOfLoggingEventsAndGet from InMemoryAppender
  because there are two methods in InMemoryAppenderAssertions
  that already provide this functionality.
* Change logback-classic to be a provided dependency.

Closes #447
Closes #448
Closes #449
  • Loading branch information
sleberknight authored Dec 23, 2023
1 parent f44f336 commit 81c6fd7
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 26 deletions.
14 changes: 6 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@
<scope>provided</scope>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-healthchecks</artifactId>
Expand Down Expand Up @@ -239,14 +245,6 @@
<scope>provided</scope>
</dependency>

<!-- test dependencies -->

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.kiwiproject.test.logback;

import static java.util.Comparator.comparing;
import static org.assertj.core.api.Assertions.assertThat;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
Expand All @@ -20,6 +19,14 @@
* The events can be accessed, ordered, and cleared.
* <p>
* <em>This is for testing purposes only, and is not at all intended for production use!</em>
* <p>
* <h3>Migration from kiwi-beta</h3>
* If you are migrating from the InMemoryAppender in kiwi-beta, note that its
* {@code assertNumberOfLoggingEventsAndGet} method does not exist in this class.
* Instead, you can get the same behavior using {@link InMemoryAppenderAssertions}.
* Specifically, you can use {@link InMemoryAppenderAssertions#hasNumberOfLoggingEvents(int)}
* or {@link InMemoryAppenderAssertions#hasNumberOfLoggingEventsAndGet(int)} if you also
* need to get the list of events.
*/
@Beta
public class InMemoryAppender extends AppenderBase<ILoggingEvent> {
Expand All @@ -35,17 +42,6 @@ public InMemoryAppender() {
this.eventMap = new ConcurrentHashMap<>();
}

/**
* Assert this appender has the expected number of logging events, and if the assertion succeeds, return a
* list containing those events.
*/
@SuppressWarnings("unused")
public List<ILoggingEvent> assertNumberOfLoggingEventsAndGet(int expectedEventCount) {
var events = orderedEvents();
assertThat(events).hasSize(expectedEventCount);
return events;
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ public static InMemoryAppenderAssertions assertThat(InMemoryAppender appender) {
return new InMemoryAppenderAssertions(appender);
}

/**
* Begin assertions for an {@link InMemoryAppender}.
* <p>
* This method is an alias for {@link #assertThat(InMemoryAppender)}.
* It can be used to avoid conflicts with AssertJ's {@code assertThat}
* so that both can be used with static imports in the same test.
*
* @param appender the appender to assert against
* @return a new InMemoryAppenderAssertions instance
*/
public static InMemoryAppenderAssertions assertThatAppender(InMemoryAppender appender) {
return assertThat(appender);
}

/**
* Assert this appender has the expected number of logging events, and if the assertion succeeds, return a
* list containing those events.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
* A JUnit 5 extension that allows testing messages logged using Logback.
* Uses {@link InMemoryAppender} to store logged messages, so that tests
* can retrieve and verify them later.
* <p>
* Please see the usage requirements in {@link #InMemoryAppenderExtension(Class)}
* and {@link #InMemoryAppenderExtension(Class, String)}, specifically
* because this extension requires that a {@link ch.qos.logback.core.Appender}
* exists at the time tests are executed.
*/
@Beta
public class InMemoryAppenderExtension implements BeforeEachCallback, AfterEachCallback {
Expand All @@ -34,6 +39,20 @@ public class InMemoryAppenderExtension implements BeforeEachCallback, AfterEachC
* {@code com.acme.space.modulator.SpaceModulatorServiceTest.class}, then the
* appender <em>must</em> be named {@code SpaceModulatorServiceTestAppender}.
* <p>
* This appender <em>must</em> exist, e.g., in your {@code logback-test.xml}
* configuration file.
* <p>
* For example, for a test named {@code MyAwesomeTest}, the
* {@code src/test/resources/logback-test.xml} must contain:
* <pre>
* &lt;appender name="MyAwesomeTestAppender"
* class="org.kiwiproject.test.logback.InMemoryAppender"/&gt;
*
* &lt;logger name="com.acme.MyAwesomeTest" level="DEBUG"&gt;
* &lt;appender-ref ref="MyAwesomeTestAppender"/&gt;
* &lt;/logger&gt;
* </pre>
* <p>
* Note also the appender <em>must</em> be an {@link InMemoryAppender}.
*
* @param loggerClass the class of the test logger
Expand All @@ -46,6 +65,25 @@ public InMemoryAppenderExtension(Class<?> loggerClass) {
* Create a new instance associated with the given Logback logger class
* which has an appender of type {@link InMemoryAppender} with the name
* {@code appenderName}.
* <p>
* This appender <em>must</em> exist, e.g., in your {@code logback-test.xml}
* configuration file.}
* <p>
* For example, for a test named {@code MyAwesomeTest}, the
* {@code src/test/resources/logback-test.xml} must contain:
* <pre>
* &lt;appender name="MyAppender"
* class="org.kiwiproject.test.logback.InMemoryAppender"/&gt;
*
* &lt;logger name="com.acme.AnAwesomeTest" level="DEBUG"&gt;
* &lt;appender-ref ref="MyAppender"/&gt;
* &lt;/logger&gt;
* </pre>
* <p>
* You then use {@code "MyAppender"} as the value for the
* {@code appenderName} argument.
* <p>
* Note also the appender <em>must</em> be an {@link InMemoryAppender}.
*
* @param loggerClass the class of the test logger
* @param appenderName the name of the {@link InMemoryAppender}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static org.assertj.core.api.Assertions.tuple;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
import static org.kiwiproject.collect.KiwiLists.first;
import static org.kiwiproject.test.logback.InMemoryAppenderAssertions.assertThatAppender;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
Expand Down Expand Up @@ -133,7 +134,7 @@ class EventAssertions {

@Test
void shouldAssertWhenEmpty() {
var events = InMemoryAppenderAssertions.assertThat(appender).hasNumberOfLoggingEventsAndGet(0);
var events = assertThatAppender(appender).hasNumberOfLoggingEventsAndGet(0);
assertThat(events).isEmpty();
}

Expand All @@ -144,7 +145,7 @@ void shouldAssertWhenContainsLoggingEvents() {

var eventsRef = new AtomicReference<List<ILoggingEvent>>();
assertThatCode(() -> {
var loggingEvents = InMemoryAppenderAssertions.assertThat(appender).hasNumberOfLoggingEventsAndGet(5);
var loggingEvents = assertThatAppender(appender).hasNumberOfLoggingEventsAndGet(5);
eventsRef.set(loggingEvents);
}).doesNotThrowAnyException();

Expand All @@ -157,7 +158,7 @@ void shouldAssertNumberOfLoggingEventsOnly() {
var messages = IntStream.range(0, 5).mapToObj(i -> "Message " + i).toArray(String[]::new);
Arrays.stream(messages).forEach(LOG::debug);

assertThatCode(() -> InMemoryAppenderAssertions.assertThat(appender).hasNumberOfLoggingEventsAndGet(5))
assertThatCode(() -> assertThatAppender(appender).hasNumberOfLoggingEventsAndGet(5))
.doesNotThrowAnyException();
}

Expand All @@ -166,7 +167,7 @@ void shouldGetOrderedLoggingEventsOnly() {
var messages = IntStream.range(0, 5).mapToObj(i -> "Message " + i).toArray(String[]::new);
Arrays.stream(messages).forEach(LOG::debug);

List<ILoggingEvent> events = InMemoryAppenderAssertions.assertThat(appender).andGetOrderedEvents();
List<ILoggingEvent> events = assertThatAppender(appender).andGetOrderedEvents();
assertThat(events).extracting(ILoggingEvent::getFormattedMessage).containsExactly(messages);
}

Expand All @@ -175,14 +176,14 @@ void shouldCheckContainsMessageWhenItExists() {
var messages = IntStream.range(0, 5).mapToObj(i -> "Message " + i).toArray(String[]::new);
Arrays.stream(messages).forEach(LOG::debug);

assertThatCode(() -> InMemoryAppenderAssertions.assertThat(appender).containsMessage("Message 0").containsMessage("Message 4"))
assertThatCode(() -> assertThatAppender(appender).containsMessage("Message 0").containsMessage("Message 4"))
.doesNotThrowAnyException();
}

@Test
void shouldCheckContainsMessageWhenItDoesNotExist() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> InMemoryAppenderAssertions.assertThat(appender).containsMessage("Message 0"));
.isThrownBy(() -> assertThatAppender(appender).containsMessage("Message 0"));
}
}
}

0 comments on commit 81c6fd7

Please sign in to comment.