Created
June 11, 2020 18:12
-
-
Save amirmv2006/27a7b385aeba1b25c2f59def7936c846 to your computer and use it in GitHub Desktop.
Mock Logging in JUnit 5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ir.amv.os.test.helper; | |
import ch.qos.logback.classic.Logger; | |
import ch.qos.logback.classic.spi.ILoggingEvent; | |
import ch.qos.logback.classic.spi.LoggingEvent; | |
import ch.qos.logback.core.Appender; | |
import java.util.Optional; | |
import java.util.function.Supplier; | |
import java.util.stream.Stream; | |
import org.junit.jupiter.api.extension.AfterEachCallback; | |
import org.junit.jupiter.api.extension.BeforeEachCallback; | |
import org.junit.jupiter.api.extension.ExtensionContext; | |
import org.junit.jupiter.api.extension.ParameterContext; | |
import org.junit.jupiter.api.extension.ParameterResolutionException; | |
import org.junit.jupiter.api.extension.ParameterResolver; | |
import org.mockito.ArgumentCaptor; | |
import org.mockito.Mockito; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.core.ResolvableType; | |
/** | |
* @author Amir | |
*/ | |
public class LogMockingExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver { | |
private Appender<ILoggingEvent> mockedAppender; | |
private ArgumentCaptor<LoggingEvent> eventCaptor; | |
private Supplier<LoggingEvent> singleLogEventSupplier; | |
private Supplier<Stream<LoggingEvent>> streamLogEventSupplier; | |
@Override | |
public boolean supportsParameter(ParameterContext parameterContext, | |
ExtensionContext extensionContext) throws ParameterResolutionException { | |
Class<?> paramType = parameterContext.getParameter().getType(); | |
Class<?> genericType = Optional.of(parameterContext.getParameter().getParameterizedType()) | |
.map(ResolvableType::forType) | |
.map(rt -> rt.getGeneric(0)) | |
.map(ResolvableType::getRawClass) | |
.orElse(null); | |
Class<?> genericGenericType = Optional.of(parameterContext.getParameter().getParameterizedType()) | |
.map(ResolvableType::forType) | |
.map(rt -> rt.getGeneric(0)) | |
.map(rt -> rt.getGeneric(0)) | |
.map(ResolvableType::getRawClass) | |
.orElse(null); | |
return paramType.isAssignableFrom(Appender.class) || | |
paramType.isAssignableFrom(ArgumentCaptor.class) || | |
(paramType.isAssignableFrom(Supplier.class) && genericType.isAssignableFrom(LoggingEvent.class)) || | |
(paramType.isAssignableFrom(Supplier.class) && genericType.isAssignableFrom(Stream.class) && genericGenericType.isAssignableFrom(LoggingEvent.class)) | |
; | |
} | |
@Override | |
public Object resolveParameter(ParameterContext parameterContext, | |
ExtensionContext extensionContext) throws ParameterResolutionException { | |
Class<?> paramType = parameterContext.getParameter().getType(); | |
Class<?> genericType = Optional.of(parameterContext.getParameter().getParameterizedType()) | |
.map(ResolvableType::forType) | |
.map(rt -> rt.getGeneric(0)) | |
.map(ResolvableType::getRawClass) | |
.orElse(null); | |
Class<?> genericGenericType = Optional.of(parameterContext.getParameter().getParameterizedType()) | |
.map(ResolvableType::forType) | |
.map(rt -> rt.getGeneric(0)) | |
.map(rt -> rt.getGeneric(0)) | |
.map(ResolvableType::getRawClass) | |
.orElse(null); | |
if (paramType.isAssignableFrom(Appender.class)) { | |
return mockedAppender; | |
} else if (paramType.isAssignableFrom(ArgumentCaptor.class)) { | |
return eventCaptor; | |
} else if (paramType.isAssignableFrom(Supplier.class) && genericType.isAssignableFrom(LoggingEvent.class)) { | |
return singleLogEventSupplier; | |
} else if (paramType.isAssignableFrom(Supplier.class) && genericType.isAssignableFrom(Stream.class) && genericGenericType.isAssignableFrom(LoggingEvent.class)) { | |
return streamLogEventSupplier; | |
} | |
return null; | |
} | |
@Override | |
public void beforeEach(ExtensionContext context) throws Exception { | |
mockedAppender = Mockito.mock(Appender.class); | |
((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)) | |
.addAppender(mockedAppender); | |
eventCaptor = ArgumentCaptor.forClass(LoggingEvent.class); | |
singleLogEventSupplier = () -> { | |
Mockito.verify(mockedAppender).doAppend(eventCaptor.capture()); | |
return eventCaptor.getValue(); | |
}; | |
streamLogEventSupplier = () -> { | |
Mockito.verify(mockedAppender, Mockito.atLeastOnce()).doAppend(eventCaptor.capture()); | |
return eventCaptor.getAllValues().stream(); | |
}; | |
} | |
@Override | |
public void afterEach(ExtensionContext context) throws Exception { | |
mockedAppender = null; | |
eventCaptor = null; | |
singleLogEventSupplier = null; | |
streamLogEventSupplier = null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage: