diff --git a/src/main/java/com/ocarlsen/test/MockLoggerExtension.java b/src/main/java/com/ocarlsen/test/MockLoggerExtension.java new file mode 100644 index 0000000..52747b5 --- /dev/null +++ b/src/main/java/com/ocarlsen/test/MockLoggerExtension.java @@ -0,0 +1,39 @@ +package com.ocarlsen.test; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionConfigurationException; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.slf4j.LoggerFactory; + +public class MockLoggerExtension implements AfterEachCallback, BeforeEachCallback { + + private final MockLoggerFactory loggerFactory; + + static MockLoggerFactory getMockLoggerFactory() { + var loggerFactory = LoggerFactory.getILoggerFactory(); + if (loggerFactory instanceof MockLoggerFactory) { + return (MockLoggerFactory) loggerFactory; + } else { + throw new ExtensionConfigurationException("The logger factory is not a MockLoggerFactory"); + } + } + + public MockLoggerExtension() { + this(getMockLoggerFactory()); + } + + MockLoggerExtension(MockLoggerFactory loggerFactory) { + this.loggerFactory = loggerFactory; + } + + @Override + public void afterEach(ExtensionContext context) throws Exception { + loggerFactory.cleanAndResetMockLoggers(); + } + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + loggerFactory.cleanAndResetMockLoggers(); + } +} diff --git a/src/main/java/com/ocarlsen/test/MockLoggerFactory.java b/src/main/java/com/ocarlsen/test/MockLoggerFactory.java index f529d6f..0ef49aa 100644 --- a/src/main/java/com/ocarlsen/test/MockLoggerFactory.java +++ b/src/main/java/com/ocarlsen/test/MockLoggerFactory.java @@ -1,12 +1,16 @@ package com.ocarlsen.test; +import java.util.ArrayList; +import java.util.List; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; /** * http://www.slf4j.org/faq.html#slf4j_compatible @@ -19,4 +23,11 @@ public class MockLoggerFactory implements ILoggerFactory { public Logger getLogger(final String name) { return nameLoggerMap.computeIfAbsent(name, key -> mock(Logger.class)); } + + void cleanAndResetMockLoggers() { + nameLoggerMap.forEach((loggerName, logger) -> { + clearInvocations(logger); + reset(logger); + }); + } } diff --git a/src/test/java/com/ocarlsen/test/MockLoggerExtensionTest.java b/src/test/java/com/ocarlsen/test/MockLoggerExtensionTest.java new file mode 100644 index 0000000..318b1c4 --- /dev/null +++ b/src/test/java/com/ocarlsen/test/MockLoggerExtensionTest.java @@ -0,0 +1,85 @@ +package com.ocarlsen.test; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +import java.lang.System.LoggerFinder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionConfigurationException; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ExtendWith(MockitoExtension.class) +class MockLoggerExtensionTest { + + @Mock + private ExtensionContext extensionContext; + @Mock + private org.junit.platform.commons.logging.Logger extensionLogger; + + private MockLoggerExtension extension; + private Logger firstLogger; + private Logger secondLogger; + + @BeforeEach + void setUp() { + var loggerFactory = new MockLoggerFactory(); + extension = new MockLoggerExtension(loggerFactory); + firstLogger = loggerFactory.getLogger("first"); + secondLogger = loggerFactory.getLogger("second"); + } + + @DisplayName("Initialize a logger finder on \"before all\" step") + @Test + void initLoggerFinderOnBeforeAll() { + assertDoesNotThrow(() -> new MockLoggerExtension()); + } + + @DisplayName("Unknown logger finder") + @Test + void unknownLoggerFinder() { + try (var loggerFactory = mockStatic(LoggerFactory.class)) { + loggerFactory.when(LoggerFactory::getILoggerFactory).thenReturn(mock(ILoggerFactory.class)); + + var exception = assertThrows(ExtensionConfigurationException.class, MockLoggerExtension::getMockLoggerFactory); + + assertEquals("The logger factory is not a MockLoggerFactory", exception.getMessage()); + } + } + + @DisplayName("Clean and reset loggers after each test") + @Test + void resetLoggersAfterEachTest() { + firstLogger.info("test message"); + secondLogger.info("another test message"); + + assertDoesNotThrow(() -> extension.afterEach(extensionContext)); + + verifyNoInteractions(extensionContext); + verifyNoInteractions(firstLogger); + verifyNoInteractions(secondLogger); + } + + @DisplayName("Clean and reset loggers before each test") + @Test + void resetLoggersBeforeEachTest() { + firstLogger.info("test message"); + secondLogger.info("another test message"); + + assertDoesNotThrow(() -> extension.beforeEach(extensionContext)); + + verifyNoInteractions(extensionContext); + verifyNoInteractions(firstLogger); + verifyNoInteractions(secondLogger); + } +} \ No newline at end of file