You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is my extension. I made this because in my business code I have lot of "if logger.isTrace() then trace else debug" ... And I need to have all code covered by tests.
But now I face a problem: I can't combine my new extension with already existing RepeatedTest and ParameterizedTest.
/**
* This little junit5 extension allows to change the log level of loggers for a {@link TestTemplate test-method}. This allows to run the same test method with different log levels.
*
* @author Andreas Höhmann
*/
@Slf4j
public class LogLevelTestTemplateInvocationContextProvider implements TestTemplateInvocationContextProvider {
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface LogLevel {
String[] loggers();
String level();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@ExtendWith(LogLevelTestTemplateInvocationContextProvider.class)
public @interface LogLevels {
LogLevel[] value();
}
@Override
public boolean supportsTestTemplate(final ExtensionContext context) {
if (context.getTestMethod().isPresent()) {
return false;
}
final Method testMethod = context.getTestMethod().get();
if (isAnnotated(testMethod, ParameterizedTest.class)) {
log.debug("Can't combined with '{}'", ParameterizedTest.class);
return false;
}
if (isAnnotated(testMethod, RepeatedTest.class)) {
log.debug("Can't combined with '{}'", RepeatedTest.class);
return false;
}
return true;
}
@Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(final ExtensionContext context) {
return context.getTestMethod()
.map(this::extractedLogLevels)
.stream()
.flatMap(Arrays::stream)
.flatMap(logLevels -> Arrays.stream(logLevels.value()))
.map(logLevel -> new LogLevelInvocationContext(logLevel, context.getRequiredTestMethod().getName()));
}
private LogLevels[] extractedLogLevels(final Method method) {
final Class<?> parentClass = method.getDeclaringClass();
final LogLevels[] classLevelAnnotations = parentClass.getAnnotationsByType(LogLevels.class);
final List<LogLevels> cl = Arrays.asList(classLevelAnnotations);
log.debug("Found {} log level annotations '{}' for method '{}' class '{}'", cl.size(), cl, method.getName(), parentClass.getName());
final LogLevels[] methodLevelAnnotations = method.getAnnotationsByType(LogLevels.class);
final List<LogLevels> ml = Arrays.asList(methodLevelAnnotations);
log.debug("Found {} log level annotations '{}' for method '{}'", ml.size(), ml, method.getName());
final Set<LogLevels> r = new HashSet<>();
r.addAll(cl);
r.addAll(ml);
log.debug("Found {} log level annotations '{}' for '{}'", r.size(), r, method.getName());
return r.toArray(new LogLevels[0]);
}
private static class LogLevelInvocationContext implements TestTemplateInvocationContext {
private final LogLevel logLevel;
private final String methodName;
LogLevelInvocationContext(final LogLevel logLevel, final String methodName) {
this.logLevel = logLevel;
this.methodName = methodName;
}
@Override
public String getDisplayName(final int invocationIndex) {
return methodName + " - Log level: " + logLevel.level();
}
@Override
public List<Extension> getAdditionalExtensions() {
return Collections.singletonList(new LogLevelExtension(logLevel));
}
}
private static class LogLevelExtension implements BeforeEachCallback, AfterEachCallback {
private final LogLevel logLevel;
private final Map<String, Level> originalLevels = new HashMap<>();
LogLevelExtension(final LogLevel logLevel) {
this.logLevel = logLevel;
}
@Override
public void beforeEach(final ExtensionContext context) {
final Level level = Level.valueOf(logLevel.level().toUpperCase());
for (final String loggerName : logLevel.loggers()) {
final Logger logger = (Logger) LoggerFactory.getLogger(loggerName);
originalLevels.put(loggerName, logger.getLevel());
logger.setLevel(level);
}
}
@Override
public void afterEach(final ExtensionContext context) {
for (final Map.Entry<String, Level> entry : originalLevels.entrySet()) {
final Logger logger = (Logger) LoggerFactory.getLogger(entry.getKey());
logger.setLevel(entry.getValue());
}
}
}
}
The problem is now that I can't combine my own LogLevelTestTemplateInvocationContextProvider extension with the ParameterizedTest extension.
So I found only a workaround to skip my extension for tests which are already annotated with ParameterizedTest or RepeatedTest.
But what I really want is my own extension which can combined with these 2 extensions.
I would like to have something like "on top of all existing" TestTemplate-Extensions ... so that I can' create even more test's based on the previously created ones .... like another loop over all calculated TestTemplateInvocationContext's or lets call it a "post-processor" for TestTemplateInvocationContext's.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
This is my extension. I made this because in my business code I have lot of "if logger.isTrace() then trace else debug" ... And I need to have all code covered by tests.
But now I face a problem: I can't combine my new extension with already existing RepeatedTest and ParameterizedTest.
This is my test:
The problem is now that I can't combine my own LogLevelTestTemplateInvocationContextProvider extension with the ParameterizedTest extension.
So I found only a workaround to skip my extension for tests which are already annotated with ParameterizedTest or RepeatedTest.
But what I really want is my own extension which can combined with these 2 extensions.
I would like to have something like "on top of all existing" TestTemplate-Extensions ... so that I can' create even more test's based on the previously created ones .... like another loop over all calculated TestTemplateInvocationContext's or lets call it a "post-processor" for TestTemplateInvocationContext's.
Hope its understandable :)
Kind regards
Andreas
Beta Was this translation helpful? Give feedback.
All reactions