Skip to content

Commit

Permalink
Log test aborted exceptions at INFO level in the TestContext framework
Browse files Browse the repository at this point in the history
Prior to this commit, any time an aborted/skipped exception was thrown
by a TestExecutionListener, the TestContextManager unconditionally
logged the exception at WARN level -- or ERROR level for
prepareTestInstance() callbacks.

Regarding the latter, an aborted/skipped exception is certainly not an
ERROR, and in general the associated log output is very verbose
(including a stack trace) and not something the user should be warned
about it.

To improve the user experience, this commit revises TestContextManager
so that it logs such exceptions at INFO level.

Specifically, the following types of exceptions are considered
aborted/skipped exceptions.

- JUnit Jupiter: org.opentest4j.TestAbortedException
- JUnit 4 org.junit.AssumptionViolatedException
- TestNG: org.testng.SkipException

Closes gh-31479
  • Loading branch information
sbrannen committed Nov 25, 2023
1 parent dbad9fd commit 95e250d
Showing 1 changed file with 63 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand Down Expand Up @@ -90,6 +92,17 @@ public class TestContextManager {

private static final Log logger = LogFactory.getLog(TestContextManager.class);

private static final Set<Class<? extends Throwable>> skippedExceptionTypes = new LinkedHashSet<>(4);

static {
// JUnit Jupiter
loadSkippedExceptionType("org.opentest4j.TestAbortedException");
// JUnit 4
loadSkippedExceptionType("org.junit.AssumptionViolatedException");
// TestNG
loadSkippedExceptionType("org.testng.SkipException");
}

private final TestContext testContext;

private final ThreadLocal<TestContext> testContextHolder;
Expand Down Expand Up @@ -247,11 +260,19 @@ public void prepareTestInstance(Object testInstance) throws Exception {
testExecutionListener.prepareTestInstance(getTestContext());
}
catch (Throwable ex) {
if (logger.isErrorEnabled()) {
if (isSkippedException(ex)) {
if (logger.isInfoEnabled()) {
logger.info("""
Caught exception while allowing TestExecutionListener [%s] to \
prepare test instance [%s]"""
.formatted(typeName(testExecutionListener), testInstance), ex);
}
}
else if (logger.isErrorEnabled()) {
logger.error("""
Caught exception while allowing TestExecutionListener [%s] to \
prepare test instance [%s]"""
.formatted(typeName(testExecutionListener), testInstance), ex);
.formatted(typeName(testExecutionListener), testInstance), ex);
}
ReflectionUtils.rethrowException(ex);
}
Expand Down Expand Up @@ -570,7 +591,15 @@ private void handleBeforeException(Throwable ex, String callbackName, TestExecut
private void logException(
Throwable ex, String callbackName, TestExecutionListener testExecutionListener, Class<?> testClass) {

if (logger.isWarnEnabled()) {
if (isSkippedException(ex)) {
if (logger.isInfoEnabled()) {
logger.info("""
Caught exception while invoking '%s' callback on TestExecutionListener [%s] \
for test class [%s]"""
.formatted(callbackName, typeName(testExecutionListener), typeName(testClass)), ex);
}
}
else if (logger.isWarnEnabled()) {
logger.warn("""
Caught exception while invoking '%s' callback on TestExecutionListener [%s] \
for test class [%s]"""
Expand All @@ -581,7 +610,15 @@ private void logException(
private void logException(Throwable ex, String callbackName, TestExecutionListener testExecutionListener,
Object testInstance, Method testMethod) {

if (logger.isWarnEnabled()) {
if (isSkippedException(ex)) {
if (logger.isInfoEnabled()) {
logger.info("""
Caught exception while invoking '%s' callback on TestExecutionListener [%s] for \
test method [%s] and test instance [%s]"""
.formatted(callbackName, typeName(testExecutionListener), testMethod, testInstance), ex);
}
}
else if (logger.isWarnEnabled()) {
logger.warn("""
Caught exception while invoking '%s' callback on TestExecutionListener [%s] for \
test method [%s] and test instance [%s]"""
Expand Down Expand Up @@ -626,4 +663,26 @@ private static String typeName(Object obj) {
return obj.getClass().getName();
}

@SuppressWarnings("unchecked")
@Nullable
private static void loadSkippedExceptionType(String name) {
try {
Class<? extends Throwable> exceptionType = (Class<? extends Throwable>)
ClassUtils.forName(name, TestContextManager.class.getClassLoader());
skippedExceptionTypes.add(exceptionType);
}
catch (ClassNotFoundException | LinkageError ex) {
// ignore
}
}

private static boolean isSkippedException(Throwable ex) {
for (Class<? extends Throwable> skippedExceptionType : skippedExceptionTypes) {
if (skippedExceptionType.isInstance(ex)) {
return true;
}
}
return false;
}

}

0 comments on commit 95e250d

Please sign in to comment.