You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ra...@apache.org on 2026/09/17 10:31:24 UTC

(logging-log4j2) 01/01: Migrate log4j-core-test to JUnit 5 and remove unused JUnit 4 rules

This is an automated email from the ASF dual-hosted git repository.

ramanathan1504 pushed a commit to branch junit5-log4j-core-test
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit ac014aedd9cbcb2d9fc35c71759480e0b6ede87c
Author: Ramanathan <ra...@gmail.com>
AuthorDate: Thu Sep 17 16:00:58 2026 +0530

    Migrate log4j-core-test to JUnit 5 and remove unused JUnit 4 rules
---
 log4j-core-test/pom.xml                            |   7 -
 .../logging/log4j/core/test/RuleChainFactory.java  |  44 ----
 .../log4j/core/test/SystemPropertyTestRule.java    |  85 -------
 .../test/junit/AbstractExternalFileCleaner.java    |  16 +-
 .../core/test/junit/CleanFoldersRuleExtension.java |  88 ++++++++
 .../logging/log4j/core/test/junit/JdbcRule.java    |  55 +++--
 .../junit/{JndiRule.java => JndiExtension.java}    |  31 +--
 .../logging/log4j/core/test/junit/JndiRule.java    |  22 +-
 .../test/junit/URLStreamHandlerFactoryRule.java    | 100 ---------
 .../log4j/core/test/junit/package-info.java        |   4 +-
 .../log4j/core/test/layout/Log4j2_1482_Test.java   |  27 ++-
 .../log4j/core/test/layout/package-info.java       |   4 +-
 .../logging/log4j/core/test/package-info.java      |   4 +-
 .../src/test/java/foo/TestFriendlyException.java   |  16 +-
 .../logging/log4j/core/LogEventFactoryTest.java    |  74 +++----
 .../log4j/core/LoggerSerializationTest.java        |  38 ++--
 ...rnResolverDoesNotEvaluateThreadContextTest.java |  31 ++-
 .../log4j/core/PatternVariableResolverTest.java    |  26 +--
 .../CsvJsonParameterLayoutFileAppenderTest.java    |  64 ++++--
 .../FailoverFailedPrimaryAppenderTest.java         |  42 ++--
 .../appender/JsonCompleteFileAppenderTest.java     |  74 +++----
 .../appender/RandomAccessFileAppenderTest.java     |  95 ++++----
 .../log4j/core/appender/SmtpAppenderAsyncTest.java |  43 ++--
 .../appender/SocketAppenderBufferSizeTest.java     |  25 +--
 .../appender/SocketAppenderSocketOptionsTest.java  |  91 ++++----
 .../core/appender/XmlCompleteFileAppenderTest.java |  80 ++++---
 .../appender/db/AbstractDatabaseAppenderTest.java  |  24 +-
 .../core/appender/db/jdbc/AbstractH2Test.java      |   8 +-
 .../jdbc/AbstractJdbcAppenderDataSourceTest.java   |  57 ++---
 .../AbstractJdbcAppenderFactoryMethodTest.java     |  68 +++---
 .../db/jdbc/AbstractJdbcDataSourceTest.java        |   8 +-
 .../db/jdbc/DataSourceConnectionSourceTest.java    |  52 ++---
 ....java => DataSourceConnectionSourceTest01.java} |  16 +-
 ....java => DataSourceConnectionSourceTest02.java} |  16 +-
 .../jdbc/DriverManagerH2ConnectionSourceTest.java  |   9 +-
 .../db/jdbc/FactoryMethodConnectionSourceTest.java |  53 ++---
 .../jdbc/JdbcAppenderColumnMappingLiteralTest.java |  53 ++---
 .../jdbc/JdbcAppenderColumnMappingPatternTest.java |  55 ++---
 .../db/jdbc/JdbcAppenderH2DataSourceTest.java      |   7 +-
 .../db/jdbc/JdbcAppenderH2FactoryMethodTest.java   |  23 +-
 .../jdbc/JdbcAppenderHsqldbFactoryMethodTest.java  |  28 +--
 .../jdbc/JdbcAppenderMapMessageDataSourceTest.java |  70 +++---
 .../jdbc/JdbcAppenderStringSubstitutionTest.java   |  31 ++-
 .../log4j/core/appender/mom/JmsAppenderTest.java   |  54 ++---
 .../mom/kafka/KafkaAppenderCloseTimeoutTest.java   |  35 +--
 .../core/appender/mom/kafka/KafkaAppenderTest.java |  78 +++----
 .../appender/nosql/NoSqlDatabaseManagerTest.java   | 245 ++++++++++-----------
 .../RandomRollingAppenderOnStartupTest.java        |  81 +++----
 .../appender/rolling/RollingAppenderCountTest.java |  37 ++--
 .../RollingAppenderCronAndSizeLookupTest.java      |  35 +--
 .../rolling/RollingAppenderCronAndSizeTest.java    |  42 ++--
 .../RollingAppenderCronEvery2DirectTest.java       |  29 +--
 .../rolling/RollingAppenderCronEvery2Test.java     |  31 +--
 .../rolling/RollingAppenderCronOnceADayTest.java   |  52 ++---
 .../appender/rolling/RollingAppenderCronTest.java  |  43 ++--
 .../RollingAppenderCustomDeleteActionTest.java     |  35 +--
 ...RollingAppenderDeleteAccumulatedCount1Test.java |  35 +--
 ...RollingAppenderDeleteAccumulatedCount2Test.java |  35 +--
 .../RollingAppenderDeleteAccumulatedSizeTest.java  |  37 ++--
 .../rolling/RollingAppenderDeleteMaxDepthTest.java |  43 ++--
 .../rolling/RollingAppenderDeleteNestedTest.java   |  35 +--
 .../RollingAppenderDeleteScriptFri13thTest.java    |  45 ++--
 .../rolling/RollingAppenderDeleteScriptTest.java   |  43 ++--
 ...ollingAppenderDirectCustomDeleteActionTest.java |  37 ++--
 .../RollingAppenderDirectWrite1906Test.java        |  46 ++--
 .../RollingAppenderDirectWriteStartupSizeTest.java |  42 ++--
 ...RollingAppenderDirectWriteWithFilenameTest.java |  36 +--
 ...llingAppenderDirectWriteWithHtmlLayoutTest.java |  35 +--
 ...lingAppenderDirectWriteWithReconfigureTest.java |  35 ++-
 .../RollingAppenderNoUnconditionalDeleteTest.java  |  86 ++++----
 .../rolling/RollingAppenderRestartTest.java        |  51 +++--
 ...RollingAppenderSizeCompressPermissionsTest.java |  57 ++---
 .../rolling/RollingAppenderSizeMaxWidthTest.java   |  82 +++----
 ....java => RollingAppenderSizeMaxWidthTest1.java} |  19 +-
 ....java => RollingAppenderSizeMaxWidthTest2.java} |  19 +-
 ....java => RollingAppenderSizeMaxWidthTest3.java} |  19 +-
 ....java => RollingAppenderSizeMaxWidthTest4.java} |  19 +-
 .../rolling/RollingAppenderSizeWithTimeTest.java   |  45 ++--
 .../RollingAppenderTimeAndSizeDirectTest.java      |  33 +--
 .../rolling/RollingAppenderTimeAndSizeTest.java    |  45 ++--
 .../appender/rolling/RollingAppenderTimeTest.java  |  29 +--
 .../rolling/RollingAppenderUncompressedTest.java   |  32 +--
 .../RollingDirectSizeTimeNewDirectoryTest.java     |  31 +--
 .../rolling/RollingDirectTimeNewDirectoryTest.java |  36 +--
 .../RollingFileAppenderInterruptedThreadTest.java  |  20 +-
 .../RollingFileAppenderReconfigureTest.java        |  14 +-
 ...nderReconfigureUndefinedSystemPropertyTest.java |  15 +-
 .../appender/rolling/RollingNewDirectoryTest.java  |  35 +--
 .../RollingRandomAppenderDirectWriteTest.java      |  33 +--
 ...gRandomAppenderDirectWriteWithFilenameTest.java |  31 +--
 ...ltRouteScriptAppenderGroovyStaticVarsTest.java} |  24 +-
 .../DefaultRouteScriptAppenderGroovyTest.java}     |  24 +-
 ...uteScriptAppenderJavaScriptStaticVarsTest.java} |  24 +-
 .../DefaultRouteScriptAppenderJavaScriptTest.java} |  24 +-
 .../routing/DefaultRouteScriptAppenderTest.java    |  79 +++----
 .../appender/routing/JsonRoutingAppender2Test.java |  34 +--
 .../appender/routing/JsonRoutingAppenderTest.java  |  34 +--
 .../routing/PropertiesRoutingAppenderTest.java     |  49 +++--
 .../RoutesScriptAppenderGroovyStaticVarsTest.java} |  21 +-
 .../RoutesScriptAppenderGroovyTest.java}           |  21 +-
 ...tesScriptAppenderJavaScriptStaticVarsTest.java} |  23 +-
 .../RoutesScriptAppenderJavaScriptTest.java}       |  23 +-
 .../appender/routing/RoutesScriptAppenderTest.java |  87 +++-----
 .../appender/routing/RoutingAppender2767Test.java  |  41 ++--
 .../appender/routing/RoutingAppender3350Test.java  |  35 +--
 .../RoutingAppenderKeyLookupEvaluationTest.java    |  59 +++--
 .../core/appender/routing/RoutingAppenderTest.java |  49 +++--
 .../routing/RoutingAppenderWithJndiTest.java       |  88 ++++----
 .../routing/RoutingAppenderWithPurgingTest.java    | 126 +++++------
 .../routing/RoutingDefaultAppenderTest.java        |  33 +--
 .../AsyncLoggersWithAsyncLoggerConfigTest.java     |  36 +--
 .../log4j/core/async/AsyncRootReloadTest.java      |  19 +-
 .../log4j/core/async/Log4j2Jira1688AsyncTest.java  |  48 ++--
 .../log4j/core/async/Log4j2Jira1688Test.java       |  48 ++--
 .../core/config/CompositeConfigurationTest.java    | 239 +++++++-------------
 .../NestedLoggingFromThrowableMessageTest.java     |  29 +--
 .../core/impl/ThreadContextDataInjectorTest.java   |  49 ++---
 .../ConcurrentLoggingWithJsonLayoutTest.java       |  16 +-
 .../log4j/core/layout/CsvLogEventLayoutTest.java   |  45 ++--
 .../log4j/core/layout/CsvParameterLayoutTest.java  | 167 +++++++++-----
 .../log4j/core/layout/JsonLayoutMillisTest.java    |  48 ++--
 .../log4j/core/layout/SerializedLayoutTest.java    |  26 +--
 .../logging/log4j/core/layout/XmlLayoutTest.java   |  76 +++----
 .../log4j/core/lookup/ContextMapLookupTest.java    |  57 +++--
 .../log4j/core/lookup/EmbeddedLdapExtension.java   | 125 +++++++++++
 .../log4j/core/lookup/InterpolatorTest.java        |  56 ++---
 .../logging/log4j/core/lookup/JndiLookupTest.java  |  20 +-
 .../core/lookup/JndiRestrictedLookupTest.java      |  38 ++--
 .../.2.x.x/4326_log4j_core_test_junit5.xml         |  12 +
 129 files changed, 2827 insertions(+), 3041 deletions(-)

diff --git a/log4j-core-test/pom.xml b/log4j-core-test/pom.xml
index ef4ea9a9ec..e0dcb98efc 100644
--- a/log4j-core-test/pom.xml
+++ b/log4j-core-test/pom.xml
@@ -337,13 +337,6 @@
       <scope>test</scope>
     </dependency>
 
-    <!-- JUnit, naturally -->
-    <dependency>
-      <groupId>org.junit.vintage</groupId>
-      <artifactId>junit-vintage-engine</artifactId>
-      <scope>test</scope>
-    </dependency>
-
     <!-- Used for Kafka appender -->
     <dependency>
       <groupId>org.apache.kafka</groupId>
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/RuleChainFactory.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/RuleChainFactory.java
deleted file mode 100644
index d6fd348ebc..0000000000
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/RuleChainFactory.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core.test;
-
-import org.junit.rules.RuleChain;
-import org.junit.rules.TestRule;
-
-/**
- * Builds JUnit {@link RuleChain}s.
- */
-public class RuleChainFactory {
-
-    /**
-     * Creates a {@link RuleChain} where the rules are evaluated in the order you pass in.
-     *
-     * @param testRules
-     *            test rules to evaluate
-     * @return a new rule chain.
-     */
-    public static RuleChain create(final TestRule... testRules) {
-        if (testRules == null || testRules.length == 0) {
-            return RuleChain.emptyRuleChain();
-        }
-        RuleChain ruleChain = RuleChain.outerRule(testRules[0]);
-        for (int i = 1; i < testRules.length; i++) {
-            ruleChain = ruleChain.around(testRules[i]);
-        }
-        return ruleChain;
-    }
-}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/SystemPropertyTestRule.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/SystemPropertyTestRule.java
deleted file mode 100644
index 18f68a94a7..0000000000
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/SystemPropertyTestRule.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core.test;
-
-import java.util.Objects;
-import java.util.function.Supplier;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * A JUnit TestRule to set and reset a system property during a test.
- */
-public class SystemPropertyTestRule implements TestRule {
-
-    public static SystemPropertyTestRule create(final String name, final String value) {
-        return new SystemPropertyTestRule(name, value);
-    }
-
-    private final String name;
-    private final Supplier<String> valueSupplier;
-    private String value;
-
-    protected SystemPropertyTestRule(final String name, final String value) {
-        this(name, () -> value);
-    }
-
-    protected SystemPropertyTestRule(final String name, final Supplier<String> value) {
-        this.name = Objects.requireNonNull(name, "name");
-        this.valueSupplier = value;
-    }
-
-    @Override
-    public Statement apply(final Statement base, final Description description) {
-        return new Statement() {
-
-            @Override
-            public void evaluate() throws Throwable {
-                final String oldValue = System.getProperty(name);
-                try {
-                    value = valueSupplier.get();
-                    System.setProperty(name, value);
-                    base.evaluate();
-                } finally {
-                    // Restore if previously set
-                    if (oldValue != null) {
-                        System.setProperty(name, oldValue);
-                    }
-                }
-            }
-        };
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public String getValue() {
-        return value;
-    }
-
-    public Supplier<String> getValueSupplier() {
-        return valueSupplier;
-    }
-
-    @Override
-    public String toString() {
-        // Value might be a secret...
-        return "SystemPropertyTestRule [name=" + name + "]";
-    }
-}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AbstractExternalFileCleaner.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AbstractExternalFileCleaner.java
index 9fa720e66e..6801d2daaa 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AbstractExternalFileCleaner.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AbstractExternalFileCleaner.java
@@ -29,13 +29,17 @@ import java.util.Map;
 import java.util.Set;
 import org.apache.logging.log4j.core.test.internal.annotation.SuppressFBWarnings;
 import org.junit.Assert;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.rules.ExternalResource;
 
 /**
  * This class should not perform logging using Log4j to avoid accidentally
  * loading or re-loading Log4j configurations.
  */
-public abstract class AbstractExternalFileCleaner extends ExternalResource {
+public abstract class AbstractExternalFileCleaner extends ExternalResource
+        implements BeforeEachCallback, AfterEachCallback {
 
     protected static final String CLEANER_MARKER = "CLEANER";
 
@@ -91,6 +95,11 @@ public abstract class AbstractExternalFileCleaner extends ExternalResource {
         }
     }
 
+    @Override
+    public void afterEach(ExtensionContext context) {
+        after();
+    }
+
     @Override
     protected void after() {
         if (cleanAfter()) {
@@ -98,6 +107,11 @@ public abstract class AbstractExternalFileCleaner extends ExternalResource {
         }
     }
 
+    @Override
+    public void beforeEach(ExtensionContext context) {
+        before();
+    }
+
     @Override
     protected void before() {
         if (cleanBefore()) {
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/CleanFoldersRuleExtension.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/CleanFoldersRuleExtension.java
new file mode 100644
index 0000000000..eae3b1a16c
--- /dev/null
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/CleanFoldersRuleExtension.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.core.test.junit;
+
+import java.util.concurrent.TimeUnit;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.status.StatusLogger;
+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;
+
+public class CleanFoldersRuleExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver {
+
+    private final String CONFIG;
+    private final String ClassName;
+    private final ClassLoader ClassNameLoader;
+    private LoggerContext context;
+    private CleanFolders cleanFolders;
+
+    public CleanFoldersRuleExtension(
+            final String DIR, final String CONFIG, final String ClassName, final ClassLoader ClassNameLoader) {
+        this.CONFIG = CONFIG;
+        this.ClassName = ClassName;
+        this.ClassNameLoader = ClassNameLoader;
+        this.cleanFolders = new CleanFolders(DIR);
+    }
+
+    public CleanFoldersRuleExtension(
+            final String DIR,
+            final String CONFIG,
+            final String ClassName,
+            final ClassLoader ClassNameLoader,
+            final boolean before,
+            final boolean after,
+            final int maxTries) {
+        this.CONFIG = CONFIG;
+        this.ClassName = ClassName;
+        this.ClassNameLoader = ClassNameLoader;
+        this.cleanFolders = new CleanFolders(before, after, maxTries, DIR);
+    }
+
+    @Override
+    public void beforeEach(final ExtensionContext ctx) throws Exception {
+        this.cleanFolders.beforeEach(ctx);
+        this.context = Configurator.initialize(ClassName, ClassNameLoader, CONFIG);
+    }
+
+    @Override
+    public void afterEach(final ExtensionContext ctx) throws Exception {
+        if (this.context != null) {
+            Configurator.shutdown(this.context, 10, TimeUnit.SECONDS);
+            StatusLogger.getLogger().reset();
+        }
+        this.cleanFolders.afterEach(ctx);
+    }
+
+    @Override
+    public boolean supportsParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext)
+            throws ParameterResolutionException {
+        // Check if the parameter is of type LoggerContext
+        return parameterContext.getParameter().getType().equals(LoggerContext.class);
+    }
+
+    @Override
+    public Object resolveParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext)
+            throws ParameterResolutionException {
+        // Return the LoggerContext instance
+        return this.context;
+    }
+}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JdbcRule.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JdbcRule.java
index 76065470d5..6406362c5c 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JdbcRule.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JdbcRule.java
@@ -23,6 +23,9 @@ import java.util.Objects;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.core.appender.db.jdbc.ConnectionSource;
 import org.apache.logging.log4j.core.test.internal.annotation.SuppressFBWarnings;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 
@@ -35,12 +38,15 @@ import org.junit.runner.Description;
  * @since 2.8
  */
 @SuppressFBWarnings("SQL_INJECTION_JDBC")
-public class JdbcRule implements TestRule {
+public class JdbcRule implements TestRule, BeforeEachCallback, AfterEachCallback {
 
     private final ConnectionSource connectionSource;
     private final String createTableStatement;
     private final String dropTableStatement;
 
+    private Connection connection;
+    private Statement statement;
+
     /**
      * Creates a JdbcRule using a {@link ConnectionSource} and a table creation statement.
      *
@@ -63,24 +69,45 @@ public class JdbcRule implements TestRule {
         return new org.junit.runners.model.Statement() {
             @Override
             public void evaluate() throws Throwable {
-                try (final Connection connection = getConnection();
-                        final Statement statement = connection.createStatement()) {
-                    try {
-                        if (StringUtils.isNotEmpty(createTableStatement)) {
-                            statement.executeUpdate(createTableStatement);
-                        }
-                        base.evaluate();
-                    } finally {
-                        if (StringUtils.isNotEmpty(dropTableStatement)) {
-                            statement.executeUpdate(dropTableStatement);
-                        }
-                        statement.execute("SHUTDOWN");
-                    }
+                try {
+                    setupConnection();
+                    base.evaluate();
+                } finally {
+                    closeConnection();
                 }
             }
         };
     }
 
+    @Override
+    public void beforeEach(ExtensionContext context) throws Exception {
+        setupConnection();
+    }
+
+    @Override
+    public void afterEach(ExtensionContext context) throws Exception {
+        closeConnection();
+    }
+
+    void setupConnection() throws SQLException {
+        connection = getConnection();
+        statement = connection.createStatement();
+
+        if (StringUtils.isNotEmpty(createTableStatement)) {
+            statement.executeUpdate(createTableStatement);
+        }
+    }
+
+    void closeConnection() throws SQLException {
+        if (StringUtils.isNotEmpty(dropTableStatement)) {
+            statement.executeUpdate(dropTableStatement);
+        }
+        statement.execute("SHUTDOWN");
+
+        statement.close();
+        connection.close();
+    }
+
     public Connection getConnection() throws SQLException {
         return connectionSource.getConnection();
     }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JndiRule.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JndiExtension.java
similarity index 56%
copy from log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JndiRule.java
copy to log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JndiExtension.java
index 17fcb9cdd9..14648f5687 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JndiRule.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JndiExtension.java
@@ -19,39 +19,30 @@ package org.apache.logging.log4j.core.test.junit;
 import java.util.Collections;
 import java.util.Map;
 import javax.naming.Context;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
 import org.springframework.mock.jndi.SimpleNamingContextBuilder;
 
 /**
- * JUnit rule to create a mock {@link Context} and bind an object to a name.
+ * JUnit Extension to create a mock {@link Context} and bind an object to a name.
  *
- * @since 2.8
  */
-public class JndiRule implements TestRule {
+public class JndiExtension implements BeforeEachCallback {
 
     private final Map<String, Object> initialBindings;
 
-    public JndiRule(final String name, final Object value) {
+    public JndiExtension(final String name, final Object value) {
         this.initialBindings = Collections.singletonMap(name, value);
     }
 
-    public JndiRule(final Map<String, Object> initialBindings) {
+    public JndiExtension(final Map<String, Object> initialBindings) {
         this.initialBindings = initialBindings;
     }
 
-    @Override
-    public Statement apply(final Statement base, final Description description) {
-        return new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                final SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
-                for (final Map.Entry<String, Object> entry : initialBindings.entrySet()) {
-                    builder.bind(entry.getKey(), entry.getValue());
-                }
-                base.evaluate();
-            }
-        };
+    public void beforeEach(ExtensionContext ctx) throws Exception {
+        final SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
+        for (final Map.Entry<String, Object> entry : initialBindings.entrySet()) {
+            builder.bind(entry.getKey(), entry.getValue());
+        }
     }
 }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JndiRule.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JndiRule.java
index 17fcb9cdd9..4c123e1ea5 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JndiRule.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/JndiRule.java
@@ -19,6 +19,9 @@ package org.apache.logging.log4j.core.test.junit;
 import java.util.Collections;
 import java.util.Map;
 import javax.naming.Context;
+import javax.naming.NamingException;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
@@ -29,7 +32,7 @@ import org.springframework.mock.jndi.SimpleNamingContextBuilder;
  *
  * @since 2.8
  */
-public class JndiRule implements TestRule {
+public class JndiRule implements TestRule, BeforeEachCallback {
 
     private final Map<String, Object> initialBindings;
 
@@ -46,12 +49,21 @@ public class JndiRule implements TestRule {
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
-                final SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
-                for (final Map.Entry<String, Object> entry : initialBindings.entrySet()) {
-                    builder.bind(entry.getKey(), entry.getValue());
-                }
+                before();
                 base.evaluate();
             }
         };
     }
+
+    private void before() throws NamingException {
+        final SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
+        for (final Map.Entry<String, Object> entry : initialBindings.entrySet()) {
+            builder.bind(entry.getKey(), entry.getValue());
+        }
+    }
+
+    @Override
+    public void beforeEach(ExtensionContext context) throws Exception {
+        before();
+    }
 }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/URLStreamHandlerFactoryRule.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/URLStreamHandlerFactoryRule.java
deleted file mode 100644
index b469508606..0000000000
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/URLStreamHandlerFactoryRule.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core.test.junit;
-
-import java.lang.reflect.Field;
-import java.net.URL;
-import java.net.URLStreamHandler;
-import java.net.URLStreamHandlerFactory;
-import java.util.Hashtable;
-import org.junit.Assert;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Installs and restores the URL URLStreamHandlerFactory before and after tests.
- * <p>
- * Might need tweaking for different JREs.
- * </p>
- * <p>
- *     Will be remove in version 3.x.
- * </p>
- */
-@Deprecated
-public class URLStreamHandlerFactoryRule implements TestRule {
-
-    public URLStreamHandlerFactoryRule() {
-        this(null);
-    }
-
-    public URLStreamHandlerFactoryRule(final URLStreamHandlerFactory newURLStreamHandlerFactory) {
-        this.newURLStreamHandlerFactory = newURLStreamHandlerFactory;
-    }
-
-    private final URLStreamHandlerFactory newURLStreamHandlerFactory;
-
-    void clearURLHandlers() throws Exception {
-        final Field handlersFields = URL.class.getDeclaredField("handlers");
-        if (handlersFields != null) {
-            if (!handlersFields.isAccessible()) {
-                handlersFields.setAccessible(true);
-            }
-            @SuppressWarnings("unchecked")
-            final Hashtable<String, URLStreamHandler> handlers =
-                    (Hashtable<String, URLStreamHandler>) handlersFields.get(null);
-            if (handlers != null) {
-                handlers.clear();
-            }
-        }
-    }
-
-    @Override
-    public Statement apply(final Statement base, final Description description) {
-        return new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                Field factoryField = null;
-                int matches = 0;
-                URLStreamHandlerFactory oldFactory = null;
-                for (final Field field : URL.class.getDeclaredFields()) {
-                    if (URLStreamHandlerFactory.class.equals(field.getType())) {
-                        factoryField = field;
-                        matches++;
-                        factoryField.setAccessible(true);
-                        oldFactory = (URLStreamHandlerFactory) factoryField.get(null);
-                        break;
-                    }
-                }
-                Assert.assertNotNull(
-                        "java.net URL does not declare a java.net.URLStreamHandlerFactory field", factoryField);
-                Assert.assertEquals(
-                        "java.net.URL declares multiple java.net.URLStreamHandlerFactory fields.",
-                        1,
-                        matches); // FIXME There is a break in the loop so always 0 or 1
-                URL.setURLStreamHandlerFactory(newURLStreamHandlerFactory);
-                try {
-                    base.evaluate();
-                } finally {
-                    clearURLHandlers();
-                    factoryField.set(null, null);
-                    URL.setURLStreamHandlerFactory(oldFactory);
-                }
-            }
-        };
-    }
-}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/package-info.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/package-info.java
index 767f0667fa..0ad7637dcd 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/package-info.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/package-info.java
@@ -20,8 +20,10 @@
  * @see org.junit.rules.TestRule
  */
 @Export
-@Version("2.25.3")
+@Version("2.27.0")
+@BaselineIgnore("2.27.0")
 package org.apache.logging.log4j.core.test.junit;
 
+import aQute.bnd.annotation.baseline.BaselineIgnore;
 import org.osgi.annotation.bundle.Export;
 import org.osgi.annotation.versioning.Version;
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/Log4j2_1482_Test.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/Log4j2_1482_Test.java
index 79f8bbd17f..6a60148f82 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/Log4j2_1482_Test.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/Log4j2_1482_Test.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.core.test.layout;
 
+import static org.junit.jupiter.api.Assertions.fail;
+
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
@@ -26,23 +28,28 @@ import java.util.Arrays;
 import java.util.List;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.Configurator;
-import org.apache.logging.log4j.core.test.categories.Layouts;
-import org.apache.logging.log4j.core.test.junit.CleanFolders;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Tests https://issues.apache.org/jira/browse/LOG4J2-1482
  */
-@Category(Layouts.Csv.class)
+@Tag("Layouts.Csv")
 public abstract class Log4j2_1482_Test {
 
     static final String CONFIG_LOCATION = "log4j2-1482.xml";
 
     static final String FOLDER = "target/log4j2-1482";
 
+    @RegisterExtension
+    private CleanFoldersRuleExtension cleanFolders = new CleanFoldersRuleExtension(
+            FOLDER,
+            CONFIG_LOCATION,
+            Log4j2_1482_Test.class.getName(),
+            this.getClass().getClassLoader());
+
     private static final int LOOP_COUNT = 10;
 
     static void assertFileContents(final int runNumber) throws IOException {
@@ -56,15 +63,11 @@ public abstract class Log4j2_1482_Test {
                 final File[] files = folder.toFile().listFiles();
                 Arrays.sort(files);
                 System.out.println("Run " + runNumber + ": " + Arrays.toString(files));
-                Assert.fail(
-                        String.format("Run %,d, line %,d of %,d: \"%s\" in %s", runNumber, i++, size, string, lines));
+                fail(String.format("Run %,d, line %,d of %,d: \"%s\" in %s", runNumber, i++, size, string, lines));
             }
         }
     }
 
-    @Rule
-    public CleanFolders cleanFolders = new CleanFolders(FOLDER);
-
     protected abstract void log(int runNumber);
 
     private void loopingRun(final int loopCount) throws IOException {
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/package-info.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/package-info.java
index d0cb234d16..915ab30576 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/package-info.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/package-info.java
@@ -15,8 +15,10 @@
  * limitations under the license.
  */
 @Export
-@Version("2.20.1")
+@Version("2.27.0")
+@BaselineIgnore("2.27.0")
 package org.apache.logging.log4j.core.test.layout;
 
+import aQute.bnd.annotation.baseline.BaselineIgnore;
 import org.osgi.annotation.bundle.Export;
 import org.osgi.annotation.versioning.Version;
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/package-info.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/package-info.java
index 8e58650f6f..95df3fb073 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/package-info.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/package-info.java
@@ -15,8 +15,8 @@
  * limitations under the license.
  */
 @Export
-@Version("2.25.3")
-@BaselineIgnore("2.25.0")
+@Version("2.27.0")
+@BaselineIgnore("2.27.0")
 package org.apache.logging.log4j.core.test;
 
 import aQute.bnd.annotation.baseline.BaselineIgnore;
diff --git a/log4j-core-test/src/test/java/foo/TestFriendlyException.java b/log4j-core-test/src/test/java/foo/TestFriendlyException.java
index f0201e04f6..c9d7a6df32 100644
--- a/log4j-core-test/src/test/java/foo/TestFriendlyException.java
+++ b/log4j-core-test/src/test/java/foo/TestFriendlyException.java
@@ -16,7 +16,10 @@
  */
 package foo;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.startsWith;
 
 import java.net.Socket;
 import java.util.Arrays;
@@ -61,7 +64,7 @@ public final class TestFriendlyException extends RuntimeException {
 
     static {
         // Ensure the distinct packaging
-        assertThat(TestFriendlyException.class.getPackage().getName()).doesNotStartWith("org.apache");
+        assertThat(TestFriendlyException.class.getPackage().getName(), not(startsWith("org.apache")));
     }
 
     private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
@@ -82,7 +85,7 @@ public final class TestFriendlyException extends RuntimeException {
                 if (stackTraceElement.getClassName().equals(socketClassName)) {
                     if (Constants.JAVA_MAJOR_VERSION > 8) {
                         final String stackTraceElementString = stackTraceElement.toString();
-                        assertThat(stackTraceElementString).startsWith("java.base/");
+                        assertThat(stackTraceElementString, startsWith("java.base/"));
                     }
                     return stackTraceElement;
                 }
@@ -138,9 +141,10 @@ public final class TestFriendlyException extends RuntimeException {
                 exceptions.add(suppressed);
             }
         }
-        assertThat(identityMalfunctioningExceptionStackTraceDepths)
-                .describedAs("# of visited exceptions = %s", visitedExceptions.size())
-                .hasSizeGreaterThan(1);
+        assertThat(
+                "# of visited exceptions = " + visitedExceptions.size(),
+                identityMalfunctioningExceptionStackTraceDepths.size(),
+                greaterThan(1));
     }
 
     private static TestFriendlyException create(
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java
index ce42d5d851..3d3ba89fa7 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java
@@ -16,8 +16,8 @@
  */
 package org.apache.logging.log4j.core;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import java.lang.reflect.Field;
 import java.util.List;
@@ -31,62 +31,52 @@ import org.apache.logging.log4j.core.impl.LocationAwareLogEventFactory;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.impl.LogEventFactory;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.core.util.Constants;
 import org.apache.logging.log4j.message.Message;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
-import org.junit.runners.model.Statement;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
 
 /**
  *
  */
 public class LogEventFactoryTest {
 
-    private static final String CONFIG = "log4j2-config.xml";
-    private static final LoggerContextRule context = new LoggerContextRule(CONFIG);
-
-    private ListAppender app;
-
-    // this would look so cool using lambdas
-    @ClassRule
-    public static RuleChain chain = RuleChain.outerRule((base, description) -> new Statement() {
-                @Override
-                public void evaluate() throws Throwable {
-                    System.setProperty(Constants.LOG4J_LOG_EVENT_FACTORY, TestLogEventFactory.class.getName());
-                    resetLogEventFactory(new TestLogEventFactory());
-                    try {
-                        base.evaluate();
-                    } finally {
-                        System.clearProperty(Constants.LOG4J_LOG_EVENT_FACTORY);
-                        resetLogEventFactory(new DefaultLogEventFactory());
-                    }
-                }
+    @BeforeAll
+    static void setupEventFactory() throws Exception {
+        System.setProperty(Constants.LOG4J_LOG_EVENT_FACTORY, TestLogEventFactory.class.getName());
+        resetLogEventFactory(new TestLogEventFactory());
+    }
 
-                private void resetLogEventFactory(final LogEventFactory logEventFactory) throws IllegalAccessException {
-                    final Field field = FieldUtils.getField(LoggerConfig.class, "LOG_EVENT_FACTORY", true);
-                    FieldUtils.removeFinalModifier(field);
-                    FieldUtils.writeStaticField(field, logEventFactory, false);
-                }
-            })
-            .around(context);
+    @AfterAll
+    static void resetEventFactory() throws Exception {
+        System.clearProperty(Constants.LOG4J_LOG_EVENT_FACTORY);
+        resetLogEventFactory(new DefaultLogEventFactory());
+    }
 
-    @Before
-    public void before() {
-        app = context.getListAppender("List").clear();
+    private static void resetLogEventFactory(final LogEventFactory logEventFactory) throws IllegalAccessException {
+        final Field field = FieldUtils.getField(LoggerConfig.class, "LOG_EVENT_FACTORY", true);
+        FieldUtils.removeFinalModifier(field);
+        FieldUtils.writeStaticField(field, logEventFactory, false);
     }
 
     @Test
-    public void testEvent() {
-        final org.apache.logging.log4j.Logger logger = context.getLogger("org.apache.test.LogEventFactory");
+    @LoggerContextSource("log4j2-config.xml")
+    public void testEvent(LoggerContext context) {
+        ListAppender app = context.getConfiguration().getAppender("List");
+        app.clear();
+
+        final Logger logger = context.getLogger("org.apache.test.LogEventFactory");
+
         logger.error("error message");
+
         final List<LogEvent> events = app.getEvents();
-        assertNotNull("No events", events);
-        assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
+        assertNotNull(events, "No events");
+        assertEquals(1, events.size(), "Incorrect number of events. Expected 1, actual " + events.size());
+
         final LogEvent event = events.get(0);
-        assertEquals("TestLogEventFactory wasn't used", "Test", event.getLoggerName());
+        assertEquals("Test", event.getLoggerName(), "TestLogEventFactory wasn't used");
     }
 
     public static class TestLogEventFactory implements LogEventFactory, LocationAwareLogEventFactory {
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java
index 1f244a2890..f23bc05e6c 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java
@@ -16,26 +16,34 @@
  */
 package org.apache.logging.log4j.core;
 
+import static org.apache.logging.log4j.test.SerializableMatchers.serializesRoundTrip;
+import static org.hamcrest.MatcherAssert.assertThat;
+
 import java.io.Serializable;
-import java.util.Arrays;
-import java.util.Collection;
+import java.util.stream.Stream;
 import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.test.AbstractSerializationTest;
-import org.junit.runners.Parameterized.Parameters;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class LoggerSerializationTest {
 
-public class LoggerSerializationTest extends AbstractSerializationTest {
+    static Stream<Serializable> data() {
+        return Stream.of(
+                new LoggerContext("").getLogger("", null),
+                (Serializable) LogManager.getRootLogger(),
+                (Serializable) LogManager.getLogger(),
+                (Serializable) LogManager.getLogger("test"));
+    }
 
-    @Parameters
-    public static Collection<Object[]> data() {
-        return Arrays.asList(new Object[][] {
-            {new LoggerContext("").getLogger("", null)},
-            {LogManager.getRootLogger()},
-            {LogManager.getLogger()},
-            {LogManager.getLogger("test")}
-        });
+    @ParameterizedTest
+    @MethodSource("data")
+    void testSerializationRoundtripEquals(final Serializable serializable) {
+        assertThat(serializable, serializesRoundTrip(serializable));
     }
 
-    public LoggerSerializationTest(final Serializable serializable) {
-        super(serializable);
+    @ParameterizedTest
+    @MethodSource("data")
+    void testSerializationRoundtripNoException(final Serializable serializable) {
+        assertThat(serializable, serializesRoundTrip());
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/PatternResolverDoesNotEvaluateThreadContextTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/PatternResolverDoesNotEvaluateThreadContextTest.java
index 20eef66435..05dd8e67ab 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/PatternResolverDoesNotEvaluateThreadContextTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/PatternResolverDoesNotEvaluateThreadContextTest.java
@@ -20,30 +20,27 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.List;
+import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Named;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
+@LoggerContextSource("log4j2-pattern-layout-with-context.xml")
 public class PatternResolverDoesNotEvaluateThreadContextTest {
 
-    private static final String CONFIG = "log4j2-pattern-layout-with-context.xml";
     private static final String PARAMETER = "user";
     private ListAppender listAppender;
 
-    @ClassRule
-    public static LoggerContextRule context = new LoggerContextRule(CONFIG);
-
-    @Before
-    public void before() {
-        listAppender = context.getRequiredAppender("list", ListAppender.class);
-        listAppender.clear();
+    @BeforeEach
+    public void beforeEach(@Named("list") final ListAppender appender) {
+        this.listAppender = appender.clear();
     }
 
     @Test
-    public void testNoUserSet() {
+    public void testNoUserSet(final LoggerContext context) {
         final Logger logger = context.getLogger(getClass());
         logger.info("This is a test");
         final List<String> messages = listAppender.getMessages();
@@ -56,7 +53,7 @@ public class PatternResolverDoesNotEvaluateThreadContextTest {
     }
 
     @Test
-    public void testMessageIsNotLookedUp() {
+    public void testMessageIsNotLookedUp(final LoggerContext context) {
         final Logger logger = context.getLogger(getClass());
         logger.info("This is a ${upper:test}");
         final List<String> messages = listAppender.getMessages();
@@ -69,7 +66,7 @@ public class PatternResolverDoesNotEvaluateThreadContextTest {
     }
 
     @Test
-    public void testUser() {
+    public void testUser(final LoggerContext context) {
         final Logger logger = context.getLogger(getClass());
         ThreadContext.put(PARAMETER, "123");
         try {
@@ -87,7 +84,7 @@ public class PatternResolverDoesNotEvaluateThreadContextTest {
     }
 
     @Test
-    public void testUserIsLookup() {
+    public void testUserIsLookup(final LoggerContext context) {
         final Logger logger = context.getLogger(getClass());
         ThreadContext.put(PARAMETER, "${java:version}");
         try {
@@ -105,7 +102,7 @@ public class PatternResolverDoesNotEvaluateThreadContextTest {
     }
 
     @Test
-    public void testUserHasLookup() {
+    public void testUserHasLookup(final LoggerContext context) {
         final Logger logger = context.getLogger(getClass());
         ThreadContext.put(PARAMETER, "user${java:version}name");
         try {
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/PatternVariableResolverTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/PatternVariableResolverTest.java
index 4b4c0739c7..841eadcc8a 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/PatternVariableResolverTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/PatternVariableResolverTest.java
@@ -16,37 +16,35 @@
  */
 package org.apache.logging.log4j.core;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.List;
+import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Named;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 /**
  * Class Description goes here.
  */
+@LoggerContextSource("log4j2-pattern-layout.xml")
 public class PatternVariableResolverTest {
 
-    private static final String CONFIG = "log4j2-pattern-layout.xml";
     private ListAppender listAppender;
 
-    @ClassRule
-    public static LoggerContextRule context = new LoggerContextRule(CONFIG);
-
-    @Before
-    public void before() {
-        listAppender = context.getRequiredAppender("list", ListAppender.class);
+    @BeforeEach
+    public void beforeEach(@Named("list") final ListAppender appender) {
+        listAppender = appender;
     }
 
     @Test
-    public void testFileName() {
+    public void testFileName(LoggerContext context) {
         final Logger logger = context.getLogger(PatternVariableResolverTest.class);
         logger.info("This is a test");
         final List<String> messages = listAppender.getMessages();
-        assertTrue("No messages returned", messages != null && !messages.isEmpty());
+        assertTrue(messages != null && !messages.isEmpty(), "No messages returned");
         final String message = messages.get(0);
         System.out.println(message);
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java
index 8502131808..df3ccff2d9 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.core.appender;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import com.google.common.io.Files;
 import java.io.File;
 import java.io.IOException;
@@ -23,30 +25,28 @@ import java.nio.charset.Charset;
 import java.util.List;
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.test.categories.Layouts;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.test.junit.CleanFiles;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Tests https://issues.apache.org/jira/browse/LOG4J2-1502
  */
-@Category(Layouts.Csv.class)
+@Tag("Layouts.Csv")
 public class CsvJsonParameterLayoutFileAppenderTest {
 
     private static final String FILE_PATH = "target/CsvJsonParameterLayoutFileAppenderTest.log";
+    private final String CONFIG = "log4j-cvs-json-parameter.xml";
 
-    private static final LoggerContextRule loggerContextRule = new LoggerContextRule("log4j-cvs-json-parameter.xml");
+    private LoggerContext loggerContext;
 
-    @Rule
-    public RuleChain rule = loggerContextRule.withCleanFilesRule(FILE_PATH);
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(FILE_PATH);
 
     private void testNoNulCharacters(final String message, final String expected) throws IOException {
         @SuppressWarnings("resource")
-        final LoggerContext loggerContext = loggerContextRule.getLoggerContext();
         final Logger logger = loggerContext.getLogger("com.example");
         logger.error("log:", message);
         loggerContext.stop();
@@ -62,53 +62,69 @@ public class CsvJsonParameterLayoutFileAppenderTest {
                 count0s++;
             }
         }
-        Assert.assertEquals("File contains " + count0s + " 0x00 byte at indices " + sb, 0, count0s);
+        assertEquals(0, count0s, "File contains " + count0s + " 0x00 byte at indices " + sb);
         final List<String> readLines = Files.readLines(file, Charset.defaultCharset());
         final String actual = readLines.get(0);
-        // Assert.assertTrue(actual, actual.contains(message));
-        Assert.assertEquals(actual, expected, actual);
-        Assert.assertEquals(1, readLines.size());
+        // assertTrue(actual, actual.contains(message));
+        assertEquals(expected, actual, actual);
+        assertEquals(1, readLines.size());
     }
 
     @Test
-    public void testNoNulCharactersDoubleQuote() throws IOException {
+    @LoggerContextSource(CONFIG)
+    public void testNoNulCharactersDoubleQuote(LoggerContext context) throws IOException {
+        this.loggerContext = context;
         // TODO This does not seem right but there is no NULs. Check Apache Commons CSV.
         testNoNulCharacters("\"", "\"\"\"\"");
     }
 
     @Test
-    public void testNoNulCharactersJson() throws IOException {
+    @LoggerContextSource(CONFIG)
+    public void testNoNulCharactersJson(LoggerContext context) throws IOException {
+        this.loggerContext = context;
         testNoNulCharacters("{\"id\":10,\"name\":\"Alice\"}", "\"{\"\"id\"\":10,\"\"name\"\":\"\"Alice\"\"}\"");
     }
 
     @Test
-    public void testNoNulCharactersOneChar() throws IOException {
+    @LoggerContextSource(CONFIG)
+    public void testNoNulCharactersOneChar(LoggerContext context) throws IOException {
+        this.loggerContext = context;
         testNoNulCharacters("A", "A");
     }
 
     @Test
-    public void testNoNulCharactersOpenCurly() throws IOException {
+    @LoggerContextSource(CONFIG)
+    public void testNoNulCharactersOpenCurly(LoggerContext context) throws IOException {
+        this.loggerContext = context;
         testNoNulCharacters("{", "{");
     }
 
     @Test
-    public void testNoNulCharactersOpenParen() throws IOException {
+    @LoggerContextSource(CONFIG)
+    public void testNoNulCharactersOpenParen(LoggerContext context) throws IOException {
+        this.loggerContext = context;
         testNoNulCharacters("(", "(");
     }
 
     @Test
-    public void testNoNulCharactersOpenSquare() throws IOException {
+    @LoggerContextSource(CONFIG)
+    public void testNoNulCharactersOpenSquare(LoggerContext context) throws IOException {
+        this.loggerContext = context;
         // TODO Why is the char quoted? Check Apache Commons CSV.
         testNoNulCharacters("[", "[");
     }
 
     @Test
-    public void testNoNulCharactersThreeChars() throws IOException {
+    @LoggerContextSource(CONFIG)
+    public void testNoNulCharactersThreeChars(LoggerContext context) throws IOException {
+        this.loggerContext = context;
         testNoNulCharacters("ABC", "ABC");
     }
 
     @Test
-    public void testNoNulCharactersXml() throws IOException {
+    @LoggerContextSource(CONFIG)
+    public void testNoNulCharactersXml(LoggerContext context) throws IOException {
+        this.loggerContext = context;
         testNoNulCharacters(
                 "<test attr1='val1' attr2=\"value2\">X</test>", "\"<test attr1='val1' attr2=\"\"value2\"\">X</test>\"");
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FailoverFailedPrimaryAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FailoverFailedPrimaryAppenderTest.java
index 9c39204b16..1199361eab 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FailoverFailedPrimaryAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/FailoverFailedPrimaryAppenderTest.java
@@ -16,41 +16,43 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import java.util.List;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.test.appender.FailOnceAppender;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Named;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 /**
  *
  */
+@LoggerContextSource("log4j-failover.xml")
 public class FailoverFailedPrimaryAppenderTest {
     private ListAppender app;
     private FailOnceAppender foApp;
     private Logger logger;
     private Logger onceLogger;
 
-    @ClassRule
-    public static LoggerContextRule init = new LoggerContextRule("log4j-failover.xml");
-
-    @Before
-    public void setUp() {
-        app = init.getListAppender("List");
-        foApp = init.getAppender("Once");
+    @BeforeEach
+    public void setUp(
+            @Named("List") final ListAppender listAppender,
+            @Named("Once") final FailOnceAppender onceAppender,
+            LoggerContext init) {
+        this.app = listAppender;
+        this.foApp = onceAppender;
         logger = init.getLogger("LoggerTest");
         onceLogger = init.getLogger("Once");
     }
 
-    @After
+    @AfterEach
     public void tearDown() {
         if (app != null) {
             app.clear();
@@ -62,12 +64,12 @@ public class FailoverFailedPrimaryAppenderTest {
         logger.error("This is a test");
         List<LogEvent> events = app.getEvents();
         assertNotNull(events);
-        assertEquals("Incorrect number of events. Should be 1 is " + events.size(), 1, events.size());
+        assertEquals(1, events.size(), "Incorrect number of events. Should be 1 is " + events.size());
         app.clear();
         logger.error("This is a test");
         events = app.getEvents();
         assertNotNull(events);
-        assertEquals("Incorrect number of events. Should be 1 is " + events.size(), 1, events.size());
+        assertEquals(1, events.size(), "Incorrect number of events. Should be 1 is " + events.size());
     }
 
     @Test
@@ -76,14 +78,14 @@ public class FailoverFailedPrimaryAppenderTest {
         onceLogger.error("Fail again");
         List<LogEvent> events = app.getEvents();
         assertNotNull(events);
-        assertEquals("Incorrect number of events. Should be 2 is " + events.size(), 2, events.size());
+        assertEquals(2, events.size(), "Incorrect number of events. Should be 2 is " + events.size());
         app.clear();
         Thread.sleep(1100);
         onceLogger.error("Fail after recovery interval");
         onceLogger.error("Second log message");
         events = app.getEvents();
-        assertEquals("Did not recover", 0, events.size());
+        assertEquals(0, events.size(), "Did not recover");
         events = foApp.drainEvents();
-        assertEquals("Incorrect number of events in primary appender", 2, events.size());
+        assertEquals(2, events.size(), "Incorrect number of events in primary appender");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
index 4d1befb11d..e3c6bd7b12 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java
@@ -16,73 +16,65 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.util.List;
+import java.util.stream.Stream;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.impl.Log4jLogEventTest;
 import org.apache.logging.log4j.core.selector.ContextSelector;
 import org.apache.logging.log4j.core.selector.CoreContextSelectors;
-import org.apache.logging.log4j.core.test.categories.Layouts;
 import org.apache.logging.log4j.core.test.junit.CleanFiles;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.core.util.ClockFactory;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.RuleChain;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
 
 /**
  * Tests a "complete" JSON file.
  */
-@RunWith(Parameterized.class)
-@Category(Layouts.Json.class)
+@Tag("Layouts.Json")
 public class JsonCompleteFileAppenderTest {
 
-    public JsonCompleteFileAppenderTest(final Class<ContextSelector> contextSelector) {
-        this.loggerContextRule = new LoggerContextRule("JsonCompleteFileAppenderTest.xml", contextSelector);
-        this.cleanFiles = new CleanFiles(logFile);
-        this.ruleChain = RuleChain.outerRule(cleanFiles).around(loggerContextRule);
-    }
+    private final File logFile = new File("target", "JsonCompleteFileAppenderTest.log");
+
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(logFile);
 
-    @BeforeClass
-    public static void beforeClass() {
+    @BeforeAll
+    public static void beforeAll() {
         System.setProperty(ClockFactory.PROPERTY_NAME, Log4jLogEventTest.FixedTimeClock.class.getName());
     }
 
-    @AfterClass
-    public static void afterClass() {
+    @AfterAll
+    public static void afterAll() {
         System.clearProperty(ClockFactory.PROPERTY_NAME);
     }
 
-    @Parameters(name = "{0}")
-    public static Class<?>[] getParameters() {
-        return CoreContextSelectors.CLASSES;
+    @MethodSource
+    public static Stream<Class<?>> getParameters() {
+        return Stream.of(CoreContextSelectors.CLASSES);
     }
 
-    private final File logFile = new File("target", "JsonCompleteFileAppenderTest.log");
-    private final LoggerContextRule loggerContextRule;
-    private final CleanFiles cleanFiles;
-
-    @Rule
-    public RuleChain ruleChain;
-
-    @Test
-    public void testFlushAtEndOfBatch() throws Exception {
-        final Logger logger = this.loggerContextRule.getLogger("com.foo.Bar");
+    @ParameterizedTest
+    @MethodSource("getParameters")
+    @LoggerContextSource("JsonCompleteFileAppenderTest.xml")
+    public void testFlushAtEndOfBatch(final Class<ContextSelector> contextSelector, final LoggerContext loggerContext)
+            throws Exception {
+        final Logger logger = loggerContext.getLogger("com.foo.Bar");
         final String logMsg = "Message flushed with immediate flush=true";
         logger.info(logMsg);
         logger.error(logMsg, new IllegalArgumentException("badarg"));
-        this.loggerContextRule.getLoggerContext().stop(); // stops async thread
+        loggerContext.getConfiguration().getLoggerContext().stop(); // stops async thread
 
         final List<String> lines = Files.readAllLines(logFile.toPath(), StandardCharsets.UTF_8);
 
@@ -103,10 +95,10 @@ public class JsonCompleteFileAppenderTest {
         for (int i = 0; i < expected.length; i++) {
             final String line = lines.get(i);
             assertTrue(
-                    "line " + i + " incorrect: [" + line + "], does not contain: [" + expected[i] + ']',
-                    line.contains(expected[i]));
+                    line.contains(expected[i]),
+                    "line " + i + " incorrect: [" + line + "], does not contain: [" + expected[i] + ']');
         }
         final String location = "testFlushAtEndOfBatch";
-        assertFalse("no location", lines.get(0).contains(location));
+        assertFalse(lines.get(0).contains(location), "no location");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppenderTest.java
index 0371bbdb2a..ecf6608777 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppenderTest.java
@@ -19,73 +19,86 @@ package org.apache.logging.log4j.core.appender;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
-import java.util.Arrays;
-import java.util.Collection;
+import java.io.IOException;
+import java.nio.file.Files;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.CleanFiles;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.hamcrest.Matcher;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
 
 /**
  * Simple tests for both the RandomAccessFileAppender and RollingRandomAccessFileAppender.
  */
-@RunWith(Parameterized.class)
 public class RandomAccessFileAppenderTest {
 
-    @Parameterized.Parameters(name = "{0}, locationEnabled={1}, type={2}")
-    public static Collection<Object[]> data() {
-        return Arrays.asList(new Object[][] {
-            {"RandomAccessFileAppenderTest", false, ".xml"},
-            {"RandomAccessFileAppenderLocationTest", true, ".xml"},
-            {"RollingRandomAccessFileAppenderTest", false, ".xml"},
-            {"RollingRandomAccessFileAppenderLocationTest", true, ".xml"},
-            {"RollingRandomAccessFileAppenderLocationPropsTest", false, ".properties"}
-        });
-    }
-
-    private final LoggerContextRule init;
-    private final CleanFiles files;
-
-    @Rule
-    public final RuleChain chain;
+    private File logFile;
 
-    private final File logFile;
-    private final boolean locationEnabled;
+    private void setLogFile(String testName) {
+        logFile = new File("target", testName + ".log");
+    }
 
-    public RandomAccessFileAppenderTest(final String testName, final boolean locationEnabled, final String type) {
-        this.init = new LoggerContextRule(testName + type);
-        this.logFile = new File("target", testName + ".log");
-        this.files = new CleanFiles(this.logFile);
-        this.locationEnabled = locationEnabled;
-        this.chain = RuleChain.outerRule(files).around(init);
+    @AfterEach
+    void cleanUp() throws IOException {
+        Files.deleteIfExists(logFile.toPath());
     }
 
-    @Test
-    public void testRandomAccessConfiguration() throws Exception {
-        final Logger logger = this.init.getLogger("com.foo.Bar");
+    private void testRandomAccessConfiguration(LoggerContext context, final boolean locationEnabled) throws Exception {
+        final Logger logger = context.getLogger("com.foo.Bar");
         final String message = "This is a test log message brought to you by Slurm.";
         logger.info(message);
-        this.init.getLoggerContext().stop(); // stop async thread
+        context.stop(); // stop async thread
 
         String line;
-        try (final BufferedReader reader = new BufferedReader(new FileReader(this.logFile))) {
+        try (final BufferedReader reader = new BufferedReader(new FileReader(logFile))) {
             line = reader.readLine();
         }
         assertNotNull(line);
         assertThat(line, containsString(message));
         final Matcher<String> containsLocationInformation = containsString("testRandomAccessConfiguration");
         final Matcher<String> containsLocationInformationIfEnabled =
-                this.locationEnabled ? containsLocationInformation : not(containsLocationInformation);
+                locationEnabled ? containsLocationInformation : not(containsLocationInformation);
         assertThat(line, containsLocationInformationIfEnabled);
     }
+
+    @Test
+    @LoggerContextSource("RandomAccessFileAppenderTest.xml")
+    public void test1(LoggerContext context) throws Exception {
+        setLogFile("RandomAccessFileAppenderTest");
+        testRandomAccessConfiguration(context, false);
+    }
+
+    @Test
+    @LoggerContextSource("RandomAccessFileAppenderLocationTest.xml")
+    public void test2(LoggerContext context) throws Exception {
+        setLogFile("RandomAccessFileAppenderLocationTest");
+        testRandomAccessConfiguration(context, true);
+    }
+
+    @Test
+    @LoggerContextSource("RollingRandomAccessFileAppenderTest.xml")
+    public void test3(LoggerContext context) throws Exception {
+        setLogFile("RollingRandomAccessFileAppenderTest");
+        testRandomAccessConfiguration(context, false);
+    }
+
+    @Test
+    @LoggerContextSource("RollingRandomAccessFileAppenderLocationTest.xml")
+    public void test4(LoggerContext context) throws Exception {
+        setLogFile("RollingRandomAccessFileAppenderLocationTest");
+        testRandomAccessConfiguration(context, true);
+    }
+
+    @Test
+    @LoggerContextSource("RollingRandomAccessFileAppenderLocationPropsTest.properties")
+    public void test5(LoggerContext context) throws Exception {
+        setLogFile("RollingRandomAccessFileAppenderLocationPropsTest");
+        testRandomAccessConfiguration(context, false);
+    }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java
index d43abc5ab2..d0f9d101e2 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java
@@ -16,22 +16,22 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.util.Iterator;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.test.AvailablePortFinder;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.core.test.smtp.SimpleSmtpServer;
 import org.apache.logging.log4j.core.test.smtp.SmtpMessage;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 public class SmtpAppenderAsyncTest {
 
@@ -39,34 +39,33 @@ public class SmtpAppenderAsyncTest {
 
     private SimpleSmtpServer smtpServer;
 
-    @BeforeClass
+    @BeforeAll
     public static void setupClass() {
         PORT = AvailablePortFinder.getNextAvailable();
         System.setProperty("smtp.port", String.valueOf(PORT));
     }
 
-    @Before
+    @BeforeEach
     public void setup() {
         smtpServer = SimpleSmtpServer.start(PORT);
     }
 
-    @Rule
-    public LoggerContextRule ctx = new LoggerContextRule("SmtpAppenderAsyncTest.xml");
-
+    @LoggerContextSource("SmtpAppenderAsyncTest.xml")
     @Test
-    public void testSync() {
-        testSmtpAppender(ctx.getLogger("sync"));
+    public void testSync(final LoggerContext ctx) {
+        testSmtpAppender(ctx.getLogger("sync"), ctx);
     }
 
+    @LoggerContextSource("SmtpAppenderAsyncTest.xml")
     @Test
-    public void testAsync() {
-        testSmtpAppender(ctx.getLogger("async"));
+    public void testAsync(final LoggerContext ctx) {
+        testSmtpAppender(ctx.getLogger("async"), ctx);
     }
 
-    private void testSmtpAppender(final Logger logger) {
+    private void testSmtpAppender(final Logger logger, final LoggerContext ctx) {
         ThreadContext.put("MDC1", "mdc1");
         logger.error("the message");
-        ctx.getLoggerContext().stop();
+        ctx.stop();
         smtpServer.stop();
 
         assertEquals(1, smtpServer.getReceivedEmailSize());
@@ -83,14 +82,14 @@ public class SmtpAppenderAsyncTest {
         }
     }
 
-    @After
+    @AfterEach
     public void teardown() {
         if (smtpServer != null) {
             smtpServer.stop();
         }
     }
 
-    @AfterClass
+    @AfterAll
     public static void teardownClass() {
         System.clearProperty("smtp.port");
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java
index 0a61efa5c2..a87f6ad700 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java
@@ -21,39 +21,34 @@ import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.SocketAppenderTest.TcpSocketTestServer;
 import org.apache.logging.log4j.core.test.AvailablePortFinder;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
 import org.apache.logging.log4j.core.util.Constants;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 /**
  *
  */
+@LoggerContextSource(value = "log4j-empty.xml", reconfigure = ReconfigurationPolicy.AFTER_EACH)
 public class SocketAppenderBufferSizeTest {
 
     private TcpSocketTestServer tcpServer;
 
-    private LoggerContext loggerContext;
     private Logger logger;
 
-    @Rule
-    public LoggerContextRule loggerContextRule = new LoggerContextRule("log4j-empty.xml");
-
-    @Before
-    public void setup() throws Exception {
+    @BeforeEach
+    public void setUp(LoggerContext context) throws Exception {
         tcpServer = new TcpSocketTestServer(AvailablePortFinder.getNextAvailable());
         tcpServer.start();
         ThreadContext.clearAll();
-        loggerContext = loggerContextRule.getLoggerContext();
-        logger = loggerContext.getLogger(SocketAppenderBufferSizeTest.class.getName());
+        this.logger = context.getLogger(SocketAppenderBufferSizeTest.class.getName());
     }
 
-    @After
+    @AfterEach
     public void teardown() {
         tcpServer.shutdown();
-        loggerContext = null;
         logger = null;
         tcpServer.reset();
         ThreadContext.clearAll();
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
index 7988c3fbd8..869a84c79c 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
@@ -16,21 +16,25 @@
  */
 package org.apache.logging.log4j.core.appender;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.Socket;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.SocketAppenderTest.TcpSocketTestServer;
 import org.apache.logging.log4j.core.net.Rfc1349TrafficClass;
 import org.apache.logging.log4j.core.net.SocketOptions;
 import org.apache.logging.log4j.core.net.TcpSocketManager;
 import org.apache.logging.log4j.core.test.AvailablePortFinder;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.core.util.NullOutputStream;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.ClassRule;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
 
 public class SocketAppenderSocketOptionsTest {
 
@@ -46,66 +50,63 @@ public class SocketAppenderSocketOptionsTest {
             throw new IllegalStateException(e);
         }
         tcpSocketTestServer.start();
-        loggerContextRule = new LoggerContextRule("log4j-socket-options.xml");
     }
 
-    @ClassRule
-    public static final LoggerContextRule loggerContextRule;
-
-    @AfterClass
-    public static void afterClass() {
+    @AfterAll
+    public static void afterAll() {
         if (tcpSocketTestServer != null) {
             tcpSocketTestServer.shutdown();
         }
     }
 
     @Test
-    public void testSocketOptions() throws IOException {
-        Assert.assertNotNull(loggerContextRule);
-        Assert.assertNotNull(loggerContextRule.getConfiguration());
-        final SocketAppender appender = loggerContextRule.getAppender("socket", SocketAppender.class);
-        Assert.assertNotNull(appender);
+    @LoggerContextSource("log4j-socket-options.xml")
+    public void testSocketOptions(final LoggerContext loggerContext) throws IOException {
+        assertNotNull(loggerContext);
+        assertNotNull(loggerContext.getConfiguration());
+        final SocketAppender appender = loggerContext.getConfiguration().getAppender("socket");
+
+        assertNotNull(appender);
         final TcpSocketManager manager = (TcpSocketManager) appender.getManager();
-        Assert.assertNotNull(manager);
+        assertNotNull(manager);
         final OutputStream outputStream = manager.getOutputStream();
-        Assert.assertFalse(outputStream instanceof NullOutputStream);
+        assertFalse(outputStream instanceof NullOutputStream);
         final SocketOptions socketOptions = manager.getSocketOptions();
-        Assert.assertNotNull(socketOptions);
+        assertNotNull(socketOptions);
         final Socket socket = manager.getSocket();
-        Assert.assertNotNull(socket);
+        assertNotNull(socket);
         // Test config request
-        Assert.assertEquals(false, socketOptions.isKeepAlive());
-        Assert.assertEquals(false, socketOptions.isOobInline());
-        Assert.assertEquals(false, socketOptions.isReuseAddress());
-        Assert.assertEquals(false, socketOptions.isTcpNoDelay());
-        Assert.assertEquals(
+        assertFalse(socketOptions.isKeepAlive());
+        assertFalse(socketOptions.isOobInline());
+        assertFalse(socketOptions.isReuseAddress());
+        assertFalse(socketOptions.isTcpNoDelay());
+        assertEquals(
                 Rfc1349TrafficClass.IPTOS_LOWCOST.value(),
                 socketOptions.getActualTrafficClass().intValue());
-        Assert.assertEquals(10000, socketOptions.getReceiveBufferSize().intValue());
-        Assert.assertEquals(8000, socketOptions.getSendBufferSize().intValue());
-        Assert.assertEquals(12345, socketOptions.getSoLinger().intValue());
-        Assert.assertEquals(54321, socketOptions.getSoTimeout().intValue());
+        assertEquals(10000, socketOptions.getReceiveBufferSize().intValue());
+        assertEquals(8000, socketOptions.getSendBufferSize().intValue());
+        assertEquals(12345, socketOptions.getSoLinger().intValue());
+        assertEquals(54321, socketOptions.getSoTimeout().intValue());
         // Test live socket
-        Assert.assertFalse(socket.getKeepAlive());
-        Assert.assertFalse(socket.getOOBInline());
-        Assert.assertFalse(socket.getReuseAddress());
-        Assert.assertFalse(socket.getTcpNoDelay());
-        // Assert.assertEquals(10000, socket.getReceiveBufferSize());
+        assertFalse(socket.getKeepAlive());
+        assertFalse(socket.getOOBInline());
+        assertFalse(socket.getReuseAddress());
+        assertFalse(socket.getTcpNoDelay());
+        // assertEquals(10000, socket.getReceiveBufferSize());
         // This settings changes while we are running, so we cannot assert it.
-        // Assert.assertEquals(8000, socket.getSendBufferSize());
-        Assert.assertEquals(12345, socket.getSoLinger());
-        Assert.assertEquals(54321, socket.getSoTimeout());
+        // assertEquals(8000, socket.getSendBufferSize());
+        assertEquals(12345, socket.getSoLinger());
+        assertEquals(54321, socket.getSoTimeout());
     }
 
     @Test
-    public void testSocketTrafficClass() throws IOException {
-        Assume.assumeTrue(
-                "Run only on Java 7",
-                System.getProperty("java.specification.version").equals("1.7"));
-        Assume.assumeFalse("Do not run on Travis CI", "true".equals(System.getenv("TRAVIS")));
-        final SocketAppender appender = loggerContextRule.getAppender("socket", SocketAppender.class);
+    @LoggerContextSource("log4j-socket-options.xml")
+    public void testSocketTrafficClass(final LoggerContext loggerContext) throws IOException {
+        assumeTrue(System.getProperty("java.specification.version").equals("1.7"), "Run only on Java 7");
+        assumeFalse("true".equals(System.getenv("TRAVIS")), "Do not run on Travis CI");
+        final SocketAppender appender = loggerContext.getConfiguration().getAppender("socket");
         final TcpSocketManager manager = (TcpSocketManager) appender.getManager();
         final Socket socket = manager.getSocket();
-        Assert.assertEquals(Rfc1349TrafficClass.IPTOS_LOWCOST.value(), socket.getTrafficClass());
+        assertEquals(Rfc1349TrafficClass.IPTOS_LOWCOST.value(), socket.getTrafficClass());
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java
index c3310ac930..64f6267428 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java
@@ -16,10 +16,10 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -27,49 +27,42 @@ import java.io.FileReader;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.util.List;
+import java.util.stream.Stream;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.selector.ContextSelector;
 import org.apache.logging.log4j.core.selector.CoreContextSelectors;
 import org.apache.logging.log4j.core.test.CoreLoggerContexts;
-import org.apache.logging.log4j.core.test.categories.Layouts;
 import org.apache.logging.log4j.core.test.junit.CleanFiles;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.RuleChain;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
 
 /**
  * Tests a "complete" XML file a.k.a. a well-formed XML file.
  */
-@RunWith(Parameterized.class)
-@Category(Layouts.Xml.class)
+@Tag("Layouts.Xml")
 public class XmlCompleteFileAppenderTest {
 
-    public XmlCompleteFileAppenderTest(final Class<ContextSelector> contextSelector) {
-        this.loggerContextRule = new LoggerContextRule("XmlCompleteFileAppenderTest.xml", contextSelector);
-        this.cleanFiles = new CleanFiles(logFile);
-        this.ruleChain = RuleChain.outerRule(cleanFiles).around(loggerContextRule);
-    }
-
-    @Parameters(name = "{0}")
-    public static Class<?>[] getParameters() {
-        return CoreContextSelectors.CLASSES;
+    @MethodSource
+    public static Stream<Class<?>> getParameters() {
+        return Stream.of(CoreContextSelectors.CLASSES);
     }
 
     private final File logFile = new File("target", "XmlCompleteFileAppenderTest.log");
-    private final LoggerContextRule loggerContextRule;
-    private final CleanFiles cleanFiles;
 
-    @Rule
-    public RuleChain ruleChain;
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(logFile);
 
-    @Test
-    public void testFlushAtEndOfBatch() throws Exception {
-        final Logger logger = this.loggerContextRule.getLogger("com.foo.Bar");
+    @ParameterizedTest
+    @MethodSource("getParameters")
+    @LoggerContextSource("XmlCompleteFileAppenderTest.xml")
+    public void testFlushAtEndOfBatch(final Class<ContextSelector> contextSelector, final LoggerContext loggerContext)
+            throws Exception {
+        loggerContext.setExternalContext(contextSelector);
+        final Logger logger = loggerContext.getLogger("com.foo.Bar");
         final String logMsg = "Message flushed with immediate flush=false";
         logger.info(logMsg);
         CoreLoggerContexts.stopLoggerContext(false, logFile); // stop async thread
@@ -93,26 +86,26 @@ public class XmlCompleteFileAppenderTest {
         }
         assertNotNull("line1", line1);
         final String msg1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
-        assertEquals("line1 incorrect: [" + line1 + "], does not contain: [" + msg1 + ']', msg1, line1);
+        assertEquals(msg1, line1, "line1 incorrect: [" + line1 + "], does not contain: [" + msg1 + ']');
 
         assertNotNull("line2", line2);
         final String msg2 = "<Events xmlns=\"http://logging.apache.org/log4j/2.0/events\">";
-        assertEquals("line2 incorrect: [" + line2 + "], does not contain: [" + msg2 + ']', msg2, line2);
+        assertEquals(msg2, line2, "line2 incorrect: [" + line2 + "], does not contain: [" + msg2 + ']');
 
         assertNotNull("line3", line3);
         final String msg3 = "<Event ";
-        assertTrue("line3 incorrect: [" + line3 + "], does not contain: [" + msg3 + ']', line3.contains(msg3));
+        assertTrue(line3.contains(msg3), "line3 incorrect: [" + line3 + "], does not contain: [" + msg3 + ']');
 
         assertNotNull("line4", line4);
         final String msg4 = "<Instant epochSecond=";
-        assertTrue("line4 incorrect: [" + line4 + "], does not contain: [" + msg4 + ']', line4.contains(msg4));
+        assertTrue(line4.contains(msg4), "line4 incorrect: [" + line4 + "], does not contain: [" + msg4 + ']');
 
         assertNotNull("line5", line5);
         final String msg5 = logMsg;
-        assertTrue("line5 incorrect: [" + line5 + "], does not contain: [" + msg5 + ']', line5.contains(msg5));
+        assertTrue(line5.contains(msg5), "line5 incorrect: [" + line5 + "], does not contain: [" + msg5 + ']');
 
         final String location = "testFlushAtEndOfBatch";
-        assertFalse("no location", line1.contains(location));
+        assertFalse(line1.contains(location), "no location");
     }
 
     /**
@@ -135,9 +128,12 @@ public class XmlCompleteFileAppenderTest {
      * </pre>
      * @throws Exception
      */
-    @Test
-    public void testChildElementsAreCorrectlyIndented() throws Exception {
-        final Logger logger = this.loggerContextRule.getLogger("com.foo.Bar");
+    @ParameterizedTest
+    @MethodSource("getParameters")
+    @LoggerContextSource("XmlCompleteFileAppenderTest.xml")
+    public void testChildElementsAreCorrectlyIndented(
+            final Class<ContextSelector> contextSelector, final LoggerContext loggerContext) throws Exception {
+        final Logger logger = loggerContext.getLogger("com.foo.Bar");
         final String firstLogMsg = "First Msg tag must be in level 2 after correct indentation";
         logger.info(firstLogMsg);
         final String secondLogMsg = "Second Msg tag must also be in level 2 after correct indentation";
@@ -167,7 +163,7 @@ public class XmlCompleteFileAppenderTest {
         };
         final List<String> lines1 = Files.readAllLines(logFile.toPath(), StandardCharsets.UTF_8);
 
-        assertEquals("number of lines", indentations.length, lines1.size());
+        assertEquals(indentations.length, lines1.size(), "number of lines");
         for (int i = 0; i < indentations.length; i++) {
             final String line = lines1.get(i);
             if (line.trim().isEmpty()) {
@@ -175,7 +171,7 @@ public class XmlCompleteFileAppenderTest {
             } else {
                 final String padding = "        ".substring(0, indentations[i]);
                 assertTrue(
-                        "Expected " + indentations[i] + " leading spaces but got: " + line, line.startsWith(padding));
+                        line.startsWith(padding), "Expected " + indentations[i] + " leading spaces but got: " + line);
             }
         }
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java
index 66d3e08781..e56a87d9de 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.db;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.ArgumentMatchers.same;
 import static org.mockito.BDDMockito.given;
@@ -32,12 +32,12 @@ import java.util.concurrent.TimeUnit;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Property;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.jupiter.MockitoExtension;
 
-@RunWith(MockitoJUnitRunner.class)
+@ExtendWith(MockitoExtension.class)
 public class AbstractDatabaseAppenderTest {
     private static class LocalAbstractDatabaseAppender extends AbstractDatabaseAppender<LocalAbstractDatabaseManager> {
 
@@ -121,16 +121,16 @@ public class AbstractDatabaseAppenderTest {
     public void testNameAndGetLayout01() {
         setUp("testName01");
 
-        assertEquals("The name is not correct.", "testName01", appender.getName());
-        assertNull("The layout should always be null.", appender.getLayout());
+        assertEquals("testName01", appender.getName(), "The name is not correct.");
+        assertNull(appender.getLayout(), "The layout should always be null.");
     }
 
     @Test
     public void testNameAndGetLayout02() {
         setUp("anotherName02");
 
-        assertEquals("The name is not correct.", "anotherName02", appender.getName());
-        assertNull("The layout should always be null.", appender.getLayout());
+        assertEquals("anotherName02", appender.getName(), "The name is not correct.");
+        assertNull(appender.getLayout(), "The layout should always be null.");
     }
 
     @Test
@@ -138,7 +138,7 @@ public class AbstractDatabaseAppenderTest {
         setUp("name");
 
         final LocalAbstractDatabaseManager oldManager = appender.getManager();
-        assertSame("The manager should be the same.", manager, oldManager);
+        assertSame(manager, oldManager, "The manager should be the same.");
 
         final LocalAbstractDatabaseManager newManager = mock(LocalAbstractDatabaseManager.class);
         appender.replaceManager(newManager);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
index bd1990746e..ceabb735c8 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
@@ -18,16 +18,16 @@ package org.apache.logging.log4j.core.appender.db.jdbc;
 
 import java.io.IOException;
 import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
 
 /**
  * Abstracts H2 test clean up.
  */
 public abstract class AbstractH2Test {
 
-    @AfterClass
-    @BeforeClass
+    @AfterAll
+    @BeforeAll
     public static void classDeleteDir() throws IOException {
         JdbcH2TestHelper.deleteDir();
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderDataSourceTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderDataSourceTest.java
index a2d904871f..dc775737c2 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderDataSourceTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderDataSourceTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mock;
 
@@ -28,36 +28,40 @@ import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
 import javax.sql.DataSource;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.test.junit.JdbcRule;
-import org.apache.logging.log4j.core.test.junit.JndiRule;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.JndiExtension;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.core.util.Throwables;
 import org.h2.util.IOUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Abstract unit test for JdbcAppender using a {@link DataSource} configuration.
  */
 public abstract class AbstractJdbcAppenderDataSourceTest extends AbstractJdbcDataSourceTest {
 
-    @Rule
-    public final RuleChain rules;
+    @RegisterExtension
+    public JndiExtension ext = new JndiExtension(createBindings());
 
+    @RegisterExtension
     private final JdbcRule jdbcRule;
 
     protected AbstractJdbcAppenderDataSourceTest(final JdbcRule jdbcRule) {
-        this.rules = RuleChain.emptyRuleChain()
-                .around(new JndiRule("java:/comp/env/jdbc/TestDataSourceAppender", createMockDataSource()))
-                .around(jdbcRule)
-                .around(new LoggerContextRule("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source.xml"));
         this.jdbcRule = jdbcRule;
     }
 
+    private Map<String, Object> createBindings() {
+        final Map<String, Object> map = new HashMap<>();
+        map.put("java:/comp/env/jdbc/TestDataSourceAppender", createMockDataSource());
+        return map;
+    }
+
     private DataSource createMockDataSource() {
         try {
             final DataSource dataSource = mock(DataSource.class);
@@ -71,6 +75,7 @@ public abstract class AbstractJdbcAppenderDataSourceTest extends AbstractJdbcDat
     }
 
     @Test
+    @LoggerContextSource("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source.xml")
     public void testDataSourceConfig() throws Exception {
         try (final Connection connection = jdbcRule.getConnectionSource().getConnection()) {
             final Error exception = new Error("Final error massage is fatal!");
@@ -89,28 +94,28 @@ public abstract class AbstractJdbcAppenderDataSourceTest extends AbstractJdbcDat
             try (final Statement statement = connection.createStatement();
                     final ResultSet resultSet = statement.executeQuery("SELECT * FROM dsLogEntry ORDER BY id")) {
 
-                assertTrue("There should be at least one row.", resultSet.next());
+                assertTrue(resultSet.next(), "There should be at least one row.");
 
                 final long date = resultSet.getTimestamp("eventDate").getTime();
-                assertTrue("The date should be later than pre-logging (1).", date >= millis);
-                assertTrue("The date should be earlier than now (1).", date <= System.currentTimeMillis());
+                assertTrue(date >= millis, "The date should be later than pre-logging (1).");
+                assertTrue(date <= System.currentTimeMillis(), "The date should be earlier than now (1).");
                 assertEquals(
-                        "The literal column is not correct (1).",
                         "Literal Value of Data Source",
-                        resultSet.getString("literalColumn"));
-                assertEquals("The level column is not correct (1).", "FATAL", resultSet.getNString("level"));
-                assertEquals("The logger column is not correct (1).", logger.getName(), resultSet.getNString("logger"));
+                        resultSet.getString("literalColumn"),
+                        "The literal column is not correct (1).");
+                assertEquals("FATAL", resultSet.getNString("level"), "The level column is not correct (1).");
+                assertEquals(logger.getName(), resultSet.getNString("logger"), "The logger column is not correct (1).");
                 assertEquals(
-                        "The message column is not correct (1).",
                         "Error from data source 02.",
-                        resultSet.getString("message"));
+                        resultSet.getString("message"),
+                        "The message column is not correct (1).");
                 assertEquals(
-                        "The exception column is not correct (1).",
                         stackTrace,
                         IOUtils.readStringAndClose(
-                                resultSet.getNClob("exception").getCharacterStream(), -1));
+                                resultSet.getNClob("exception").getCharacterStream(), -1),
+                        "The exception column is not correct (1).");
 
-                assertFalse("There should not be two rows.", resultSet.next());
+                assertFalse(resultSet.next(), "There should not be two rows.");
             }
         }
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderFactoryMethodTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderFactoryMethodTest.java
index 4c1c29b0a2..fc51f3c9d0 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderFactoryMethodTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderFactoryMethodTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintWriter;
@@ -31,28 +31,20 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.test.junit.JdbcRule;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
 import org.apache.logging.log4j.util.Strings;
 import org.h2.util.IOUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Abstract unit test for JdbcAppender using a {@link FactoryMethodConnectionSource} configuration.
  */
 public abstract class AbstractJdbcAppenderFactoryMethodTest {
 
-    @Rule
-    public final RuleChain rules;
-
+    @RegisterExtension
     private final JdbcRule jdbcRule;
 
-    protected AbstractJdbcAppenderFactoryMethodTest(final JdbcRule jdbcRule, final String databaseType) {
-        this.rules = RuleChain.emptyRuleChain()
-                .around(jdbcRule)
-                .around(new LoggerContextRule("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-" + databaseType
-                        + "-factory-method.xml"));
+    protected AbstractJdbcAppenderFactoryMethodTest(final JdbcRule jdbcRule) {
         this.jdbcRule = jdbcRule;
     }
 
@@ -76,53 +68,53 @@ public abstract class AbstractJdbcAppenderFactoryMethodTest {
             try (final Statement statement = connection.createStatement();
                     final ResultSet resultSet = statement.executeQuery("SELECT * FROM fmLogEntry ORDER BY id")) {
 
-                assertTrue("There should be at least one row.", resultSet.next());
+                assertTrue(resultSet.next(), "There should be at least one row.");
 
                 long date = resultSet.getTimestamp("eventDate").getTime();
                 long anotherDate = resultSet.getTimestamp("anotherDate").getTime();
                 assertEquals(date, anotherDate);
-                assertTrue("The date should be later than pre-logging (1).", date >= millis);
-                assertTrue("The date should be earlier than now (1).", date <= System.currentTimeMillis());
+                assertTrue(date >= millis, "The date should be later than pre-logging (1).");
+                assertTrue(date <= System.currentTimeMillis(), "The date should be earlier than now (1).");
                 assertEquals(
-                        "The literal column is not correct (1).",
                         "Some Other Literal Value",
-                        resultSet.getString("literalColumn"));
-                assertEquals("The level column is not correct (1).", "DEBUG", resultSet.getNString("level"));
-                assertEquals("The logger column is not correct (1).", logger.getName(), resultSet.getNString("logger"));
+                        resultSet.getString("literalColumn"),
+                        "The literal column is not correct (1).");
+                assertEquals("DEBUG", resultSet.getNString("level"), "The level column is not correct (1).");
+                assertEquals(logger.getName(), resultSet.getNString("logger"), "The logger column is not correct (1).");
                 assertEquals(
-                        "The message column is not correct (1).",
                         "Factory logged message 01.",
-                        resultSet.getString("message"));
+                        resultSet.getString("message"),
+                        "The message column is not correct (1).");
                 assertEquals(
-                        "The exception column is not correct (1).",
                         Strings.EMPTY,
                         IOUtils.readStringAndClose(
-                                resultSet.getNClob("exception").getCharacterStream(), -1));
+                                resultSet.getNClob("exception").getCharacterStream(), -1),
+                        "The exception column is not correct (1).");
 
-                assertTrue("There should be two rows.", resultSet.next());
+                assertTrue(resultSet.next(), "There should be two rows.");
 
                 date = resultSet.getTimestamp("eventDate").getTime();
                 anotherDate = resultSet.getTimestamp("anotherDate").getTime();
                 assertEquals(date, anotherDate);
-                assertTrue("The date should be later than pre-logging (2).", date >= millis);
-                assertTrue("The date should be earlier than now (2).", date <= System.currentTimeMillis());
+                assertTrue(date >= millis, "The date should be later than pre-logging (2).");
+                assertTrue(date <= System.currentTimeMillis(), "The date should be earlier than now (2).");
                 assertEquals(
-                        "The literal column is not correct (2).",
                         "Some Other Literal Value",
-                        resultSet.getString("literalColumn"));
-                assertEquals("The level column is not correct (2).", "ERROR", resultSet.getNString("level"));
-                assertEquals("The logger column is not correct (2).", logger.getName(), resultSet.getNString("logger"));
+                        resultSet.getString("literalColumn"),
+                        "The literal column is not correct (2).");
+                assertEquals("ERROR", resultSet.getNString("level"), "The level column is not correct (2).");
+                assertEquals(logger.getName(), resultSet.getNString("logger"), "The logger column is not correct (2).");
                 assertEquals(
-                        "The message column is not correct (2).",
                         "Error from factory 02.",
-                        resultSet.getString("message"));
+                        resultSet.getString("message"),
+                        "The message column is not correct (2).");
                 assertEquals(
-                        "The exception column is not correct (2).",
                         stackTrace,
                         IOUtils.readStringAndClose(
-                                resultSet.getNClob("exception").getCharacterStream(), -1));
+                                resultSet.getNClob("exception").getCharacterStream(), -1),
+                        "The exception column is not correct (2).");
 
-                assertFalse("There should not be three rows.", resultSet.next());
+                assertFalse(resultSet.next(), "There should not be three rows.");
             }
         }
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcDataSourceTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcDataSourceTest.java
index 4167bdc678..cde3af4a27 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcDataSourceTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcDataSourceTest.java
@@ -17,20 +17,20 @@
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
 import javax.sql.DataSource;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
 
 /**
  * Abstract unit test for JDBC using a {@link DataSource} configuration.
  */
 public abstract class AbstractJdbcDataSourceTest {
 
-    @AfterClass
+    @AfterAll
     public static void afterClass() {
         System.clearProperty("log4j2.enableJndiJdbc");
     }
 
-    @BeforeClass
+    @BeforeAll
     public static void beforeClass() {
         System.setProperty("log4j2.enableJndiJdbc", "true");
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest.java
index d90d45ee0a..97dad51de9 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest.java
@@ -16,10 +16,10 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mock;
 
@@ -27,31 +27,21 @@ import java.sql.Connection;
 import java.sql.SQLException;
 import javax.sql.DataSource;
 import org.apache.logging.log4j.core.test.junit.JndiRule;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class DataSourceConnectionSourceTest extends AbstractJdbcDataSourceTest {
-
-    @Parameterized.Parameters(name = "{0}")
-    public static Object[][] data() {
-        return new Object[][] {{"java:/comp/env/jdbc/Logging01"}, {"java:/comp/env/jdbc/Logging02"}};
-    }
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-    private static final String CONFIG = "log4j-fatalOnly.xml";
+@LoggerContextSource("log4j-fatalOnly.xml")
+public abstract class DataSourceConnectionSourceTest extends AbstractJdbcDataSourceTest {
 
-    @Rule
-    public final RuleChain rules;
+    @RegisterExtension
+    private JndiRule jndiRule;
 
     private final DataSource dataSource = mock(DataSource.class);
     private final String jndiURL;
 
     public DataSourceConnectionSourceTest(final String jndiURL) {
-        this.rules = RuleChain.outerRule(new JndiRule(jndiURL, dataSource)).around(new LoggerContextRule(CONFIG));
+        this.jndiRule = new JndiRule(jndiURL, dataSource);
         this.jndiURL = jndiURL;
     }
 
@@ -59,21 +49,21 @@ public class DataSourceConnectionSourceTest extends AbstractJdbcDataSourceTest {
     public void testNullJndiName() {
         final DataSourceConnectionSource source = DataSourceConnectionSource.createConnectionSource(null);
 
-        assertNull("The connection source should be null.", source);
+        assertNull(source, "The connection source should be null.");
     }
 
     @Test
     public void testEmptyJndiName() {
         final DataSourceConnectionSource source = DataSourceConnectionSource.createConnectionSource("");
 
-        assertNull("The connection source should be null.", source);
+        assertNull(source, "The connection source should be null.");
     }
 
     @Test
     public void testNoDataSource() {
         final DataSourceConnectionSource source = DataSourceConnectionSource.createConnectionSource(jndiURL + "123");
 
-        assertNull("The connection source should be null.", source);
+        assertNull(source, "The connection source should be null.");
     }
 
     @Test
@@ -85,17 +75,17 @@ public class DataSourceConnectionSourceTest extends AbstractJdbcDataSourceTest {
 
             DataSourceConnectionSource source = DataSourceConnectionSource.createConnectionSource(jndiURL);
 
-            assertNotNull("The connection source should not be null.", source);
+            assertNotNull(source, "The connection source should not be null.");
             assertEquals(
-                    "The toString value is not correct.",
                     "dataSource{ name=" + jndiURL + ", value=" + dataSource + " }",
-                    source.toString());
-            assertSame("The connection is not correct (1).", connection1, source.getConnection());
-            assertSame("The connection is not correct (2).", connection2, source.getConnection());
+                    source.toString(),
+                    "The toString value is not correct.");
+            assertSame(connection1, source.getConnection(), "The connection is not correct (1).");
+            assertSame(connection2, source.getConnection(), "The connection is not correct (2).");
 
             source = DataSourceConnectionSource.createConnectionSource(jndiURL.substring(0, jndiURL.length() - 1));
 
-            assertNull("The connection source should be null now.", source);
+            assertNull(source, "The connection source should be null now.");
         }
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest01.java
similarity index 69%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest01.java
index bd1990746e..4b56585bed 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest01.java
@@ -16,19 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
-import java.io.IOException;
-import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+public class DataSourceConnectionSourceTest01 extends DataSourceConnectionSourceTest {
 
-/**
- * Abstracts H2 test clean up.
- */
-public abstract class AbstractH2Test {
-
-    @AfterClass
-    @BeforeClass
-    public static void classDeleteDir() throws IOException {
-        JdbcH2TestHelper.deleteDir();
+    public DataSourceConnectionSourceTest01() {
+        super("java:/comp/env/jdbc/Logging01");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest02.java
similarity index 69%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest02.java
index bd1990746e..cd727f470e 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest02.java
@@ -16,19 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
-import java.io.IOException;
-import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+public class DataSourceConnectionSourceTest02 extends DataSourceConnectionSourceTest {
 
-/**
- * Abstracts H2 test clean up.
- */
-public abstract class AbstractH2Test {
-
-    @AfterClass
-    @BeforeClass
-    public static void classDeleteDir() throws IOException {
-        JdbcH2TestHelper.deleteDir();
+    public DataSourceConnectionSourceTest02() {
+        super("java:/comp/env/jdbc/Logging02");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerH2ConnectionSourceTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerH2ConnectionSourceTest.java
index 57096af936..a4b889197c 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerH2ConnectionSourceTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerH2ConnectionSourceTest.java
@@ -16,12 +16,13 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
 import java.sql.Connection;
 import java.sql.SQLException;
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.Assert;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 public class DriverManagerH2ConnectionSourceTest extends AbstractH2Test {
 
@@ -40,7 +41,7 @@ public class DriverManagerH2ConnectionSourceTest extends AbstractH2Test {
                 .build();
         // @formatter:on
         try (final Connection conn = source.getConnection()) {
-            Assert.assertFalse(conn.isClosed());
+            assertFalse(conn.isClosed());
         }
     }
 
@@ -54,7 +55,7 @@ public class DriverManagerH2ConnectionSourceTest extends AbstractH2Test {
                 .build();
         // @formatter:on
         try (final Connection conn = source.getConnection()) {
-            Assert.assertFalse(conn.isClosed());
+            assertFalse(conn.isClosed());
         }
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSourceTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSourceTest.java
index b9bcf18d59..27e58205fe 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSourceTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSourceTest.java
@@ -16,29 +16,25 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mock;
 
 import java.sql.Connection;
 import java.sql.SQLException;
 import javax.sql.DataSource;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.After;
-import org.junit.ClassRule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
 
+@LoggerContextSource("log4j-fatalOnly.xml")
 public class FactoryMethodConnectionSourceTest {
     private static final ThreadLocal<Object> holder = new ThreadLocal<>();
-    private static final String CONFIG = "log4j-fatalOnly.xml";
 
-    @ClassRule
-    public static LoggerContextRule ctx = new LoggerContextRule(CONFIG);
-
-    @After
+    @AfterEach
     public void tearDown() {
         holder.remove();
     }
@@ -47,8 +43,7 @@ public class FactoryMethodConnectionSourceTest {
     public void testNoClassName() {
         final FactoryMethodConnectionSource source =
                 FactoryMethodConnectionSource.createConnectionSource(null, "method");
-
-        assertNull("The connection source should be null.", source);
+        assertNull(source, "The connection source should be null.");
     }
 
     @Test
@@ -56,7 +51,7 @@ public class FactoryMethodConnectionSourceTest {
         final FactoryMethodConnectionSource source =
                 FactoryMethodConnectionSource.createConnectionSource("someClass", null);
 
-        assertNull("The connection source should be null.", source);
+        assertNull(source, "The connection source should be null.");
     }
 
     @Test
@@ -64,7 +59,7 @@ public class FactoryMethodConnectionSourceTest {
         final FactoryMethodConnectionSource source =
                 FactoryMethodConnectionSource.createConnectionSource("org.apache.BadClass", "factoryMethod");
 
-        assertNull("The connection source should be null.", source);
+        assertNull(source, "The connection source should be null.");
     }
 
     @Test
@@ -72,7 +67,7 @@ public class FactoryMethodConnectionSourceTest {
         final FactoryMethodConnectionSource source = FactoryMethodConnectionSource.createConnectionSource(
                 this.getClass().getName(), "factoryMethod");
 
-        assertNull("The connection source should be null.", source);
+        assertNull(source, "The connection source should be null.");
     }
 
     @Test
@@ -80,7 +75,7 @@ public class FactoryMethodConnectionSourceTest {
         final FactoryMethodConnectionSource source = FactoryMethodConnectionSource.createConnectionSource(
                 BadReturnTypeFactory.class.getName(), "factoryMethod01");
 
-        assertNull("The connection source should be null.", source);
+        assertNull(source, "The connection source should be null.");
     }
 
     @Test
@@ -96,14 +91,14 @@ public class FactoryMethodConnectionSourceTest {
             final FactoryMethodConnectionSource source = FactoryMethodConnectionSource.createConnectionSource(
                     DataSourceFactory.class.getName(), "factoryMethod02");
 
-            assertNotNull("The connection source should not be null.", source);
+            assertNotNull(source, "The connection source should not be null.");
             assertEquals(
-                    "The toString value is not correct.",
                     "factory{ public static javax.sql.DataSource[" + dataSource + "] "
                             + DataSourceFactory.class.getName() + ".factoryMethod02() }",
-                    source.toString());
-            assertSame("The connection is not correct (1).", connection1, source.getConnection());
-            assertSame("The connection is not correct (2).", connection2, source.getConnection());
+                    source.toString(),
+                    "The toString value is not correct.");
+            assertSame(connection1, source.getConnection(), "The connection is not correct (1).");
+            assertSame(connection2, source.getConnection(), "The connection is not correct (2).");
         }
     }
 
@@ -116,14 +111,14 @@ public class FactoryMethodConnectionSourceTest {
             final FactoryMethodConnectionSource source = FactoryMethodConnectionSource.createConnectionSource(
                     ConnectionFactory.class.getName(), "anotherMethod03");
 
-            assertNotNull("The connection source should not be null.", source);
+            assertNotNull(source, "The connection source should not be null.");
             assertEquals(
-                    "The toString value is not correct.",
                     "factory{ public static java.sql.Connection " + ConnectionFactory.class.getName()
                             + ".anotherMethod03() }",
-                    source.toString());
-            assertSame("The connection is not correct (1).", connection, source.getConnection());
-            assertSame("The connection is not correct (2).", connection, source.getConnection());
+                    source.toString(),
+                    "The toString value is not correct.");
+            assertSame(connection, source.getConnection(), "The connection is not correct (1).");
+            assertSame(connection, source.getConnection(), "The connection is not correct (2).");
         }
     }
 
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderColumnMappingLiteralTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderColumnMappingLiteralTest.java
index deed8e9030..25724bf40a 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderColumnMappingLiteralTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderColumnMappingLiteralTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintWriter;
@@ -27,36 +27,21 @@ import java.sql.ResultSet;
 import java.sql.Statement;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.RuleChainFactory;
 import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
 import org.apache.logging.log4j.core.test.junit.JdbcRule;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.h2.util.IOUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
+@LoggerContextSource("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-dm-column-mapping-literal.xml")
 public class JdbcAppenderColumnMappingLiteralTest extends AbstractH2Test {
 
-    @Rule
-    public final RuleChain rules;
-
-    private final JdbcRule jdbcRule;
-
-    public JdbcAppenderColumnMappingLiteralTest() {
-        this(new JdbcRule(
-                JdbcH2TestHelper.TEST_CONFIGURATION_SOURCE_TMPDIR,
-                "CREATE TABLE dsMappingLogEntry (id INTEGER, level VARCHAR(10), logger VARCHAR(255), message VARCHAR(1024), exception CLOB)",
-                "DROP TABLE IF EXISTS dsMappingLogEntry"));
-    }
-
-    protected JdbcAppenderColumnMappingLiteralTest(final JdbcRule jdbcRule) {
-        this.rules = RuleChainFactory.create(
-                jdbcRule,
-                new LoggerContextRule(
-                        "org/apache/logging/log4j/core/appender/db/jdbc/log4j2-dm-column-mapping-literal.xml"));
-        this.jdbcRule = jdbcRule;
-    }
+    @RegisterExtension
+    private final JdbcRule jdbcRule = new JdbcRule(
+            JdbcH2TestHelper.TEST_CONFIGURATION_SOURCE_TMPDIR,
+            "CREATE TABLE dsMappingLogEntry (id INTEGER, level VARCHAR(10), logger VARCHAR(255), message VARCHAR(1024), exception CLOB)",
+            "DROP TABLE IF EXISTS dsMappingLogEntry");
 
     @Test
     public void test() throws Exception {
@@ -75,18 +60,18 @@ public class JdbcAppenderColumnMappingLiteralTest extends AbstractH2Test {
             try (final Statement statement = connection.createStatement();
                     final ResultSet resultSet = statement.executeQuery("SELECT * FROM dsMappingLogEntry ORDER BY id")) {
 
-                assertTrue("There should be at least one row.", resultSet.next());
+                assertTrue(resultSet.next(), "There should be at least one row.");
 
-                assertEquals("The level column is not correct (1).", "FATAL", resultSet.getNString("level"));
-                assertEquals("The logger column is not correct (1).", logger.getName(), resultSet.getNString("logger"));
-                assertEquals("The message column is not correct (1).", "Hello World!", resultSet.getString("message"));
+                assertEquals("FATAL", resultSet.getNString("level"), "The level column is not correct (1).");
+                assertEquals(logger.getName(), resultSet.getNString("logger"), "The logger column is not correct (1).");
+                assertEquals("Hello World!", resultSet.getString("message"), "The message column is not correct (1).");
                 assertEquals(
-                        "The exception column is not correct (1).",
                         stackTrace,
                         IOUtils.readStringAndClose(
-                                resultSet.getNClob("exception").getCharacterStream(), -1));
+                                resultSet.getNClob("exception").getCharacterStream(), -1),
+                        "The exception column is not correct (1).");
 
-                assertFalse("There should not be two rows.", resultSet.next());
+                assertFalse(resultSet.next(), "There should not be two rows.");
             }
         }
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderColumnMappingPatternTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderColumnMappingPatternTest.java
index a080f203fa..550dae5c6d 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderColumnMappingPatternTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderColumnMappingPatternTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintWriter;
@@ -27,37 +27,22 @@ import java.sql.ResultSet;
 import java.sql.Statement;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.RuleChainFactory;
 import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
 import org.apache.logging.log4j.core.test.junit.JdbcRule;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.h2.util.IOUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class JdbcAppenderColumnMappingPatternTest extends AbstractH2Test {
 
-    @Rule
-    public final RuleChain rules;
-
-    private final JdbcRule jdbcRule;
-
-    public JdbcAppenderColumnMappingPatternTest() {
-        this(new JdbcRule(
-                JdbcH2TestHelper.TEST_CONFIGURATION_SOURCE_MEM,
-                "CREATE TABLE dsMappingLogEntry (id INTEGER, level VARCHAR(10), logger VARCHAR(255), message VARCHAR(1024), exception CLOB)",
-                "DROP TABLE IF EXISTS dsMappingLogEntry"));
-    }
-
-    protected JdbcAppenderColumnMappingPatternTest(final JdbcRule jdbcRule) {
-        this.rules = RuleChainFactory.create(
-                jdbcRule,
-                new LoggerContextRule(
-                        "org/apache/logging/log4j/core/appender/db/jdbc/log4j2-dm-column-mapping-pattern.xml"));
-        this.jdbcRule = jdbcRule;
-    }
+    @RegisterExtension
+    private final JdbcRule jdbcRule = new JdbcRule(
+            JdbcH2TestHelper.TEST_CONFIGURATION_SOURCE_MEM,
+            "CREATE TABLE dsMappingLogEntry (id INTEGER, level VARCHAR(10), logger VARCHAR(255), message VARCHAR(1024), exception CLOB)",
+            "DROP TABLE IF EXISTS dsMappingLogEntry");
 
+    @LoggerContextSource("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-dm-column-mapping-pattern.xml")
     @Test
     public void test() throws Exception {
         try (final Connection connection = jdbcRule.getConnection()) {
@@ -75,21 +60,21 @@ public class JdbcAppenderColumnMappingPatternTest extends AbstractH2Test {
             try (final Statement statement = connection.createStatement();
                     final ResultSet resultSet = statement.executeQuery("SELECT * FROM dsMappingLogEntry ORDER BY id")) {
 
-                assertTrue("There should be at least one row.", resultSet.next());
+                assertTrue(resultSet.next(), "There should be at least one row.");
 
-                assertEquals("The level column is not correct (1).", "FATAL", resultSet.getNString("level"));
-                assertEquals("The logger column is not correct (1).", logger.getName(), resultSet.getNString("logger"));
+                assertEquals("FATAL", resultSet.getNString("level"), "The level column is not correct (1).");
+                assertEquals(logger.getName(), resultSet.getNString("logger"), "The logger column is not correct (1).");
                 assertEquals(
-                        "The message column is not correct (1).",
                         "Error from data source 02.",
-                        resultSet.getString("message"));
+                        resultSet.getString("message"),
+                        "The message column is not correct (1).");
                 assertEquals(
-                        "The exception column is not correct (1).",
                         stackTrace,
                         IOUtils.readStringAndClose(
-                                resultSet.getNClob("exception").getCharacterStream(), -1));
+                                resultSet.getNClob("exception").getCharacterStream(), -1),
+                        "The exception column is not correct (1).");
 
-                assertFalse("There should not be two rows.", resultSet.next());
+                assertFalse(resultSet.next(), "There should not be two rows.");
             }
         }
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2DataSourceTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2DataSourceTest.java
index a9c7e624e2..7e20a712bc 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2DataSourceTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2DataSourceTest.java
@@ -19,19 +19,20 @@ package org.apache.logging.log4j.core.appender.db.jdbc;
 import java.io.IOException;
 import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
 import org.apache.logging.log4j.core.test.junit.JdbcRule;
-import org.junit.Before;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 
 /**
  *
  */
 public class JdbcAppenderH2DataSourceTest extends AbstractJdbcAppenderDataSourceTest {
 
-    @Before
+    @AfterEach
     public void afterEachDeleteDir() throws IOException {
         JdbcH2TestHelper.deleteDir();
     }
 
-    @Before
+    @BeforeEach
     public void beforeEachDeleteDir() throws IOException {
         JdbcH2TestHelper.deleteDir();
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2FactoryMethodTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2FactoryMethodTest.java
index ad49fb552a..0ee8515007 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2FactoryMethodTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2FactoryMethodTest.java
@@ -21,30 +21,31 @@ import java.sql.Connection;
 import java.sql.SQLException;
 import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
 import org.apache.logging.log4j.core.test.junit.JdbcRule;
-import org.junit.Before;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 
 /**
  *
  */
+@LoggerContextSource("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-h2-factory-method.xml")
 public class JdbcAppenderH2FactoryMethodTest extends AbstractJdbcAppenderFactoryMethodTest {
 
     public JdbcAppenderH2FactoryMethodTest() {
-        super(
-                new JdbcRule(
-                        JdbcH2TestHelper.TEST_CONFIGURATION_SOURCE_MEM,
-                        "CREATE TABLE fmLogEntry ("
-                                + "id INTEGER, eventDate DATETIME, literalColumn VARCHAR(255), level NVARCHAR(10), "
-                                + "logger NVARCHAR(255), message VARCHAR(1024), exception NCLOB, anotherDate TIMESTAMP)",
-                        "DROP TABLE IF EXISTS fmLogEntry"),
-                "h2");
+        super(new JdbcRule(
+                JdbcH2TestHelper.TEST_CONFIGURATION_SOURCE_MEM,
+                "CREATE TABLE fmLogEntry ("
+                        + "id INTEGER, eventDate DATETIME, literalColumn VARCHAR(255), level NVARCHAR(10), "
+                        + "logger NVARCHAR(255), message VARCHAR(1024), exception NCLOB, anotherDate TIMESTAMP)",
+                "DROP TABLE IF EXISTS fmLogEntry"));
     }
 
-    @Before
+    @AfterEach
     public void afterEachDeleteDir() throws IOException {
         JdbcH2TestHelper.deleteDir();
     }
 
-    @Before
+    @BeforeEach
     public void beforeEachDeleteDir() throws IOException {
         JdbcH2TestHelper.deleteDir();
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderHsqldbFactoryMethodTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderHsqldbFactoryMethodTest.java
index a9a5c31801..03edd7505a 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderHsqldbFactoryMethodTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderHsqldbFactoryMethodTest.java
@@ -20,27 +20,27 @@ import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
 import org.apache.logging.log4j.core.test.junit.JdbcRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 
 /**
  *
  */
+@LoggerContextSource("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-hsqldb-factory-method.xml")
 public class JdbcAppenderHsqldbFactoryMethodTest extends AbstractJdbcAppenderFactoryMethodTest {
 
     public JdbcAppenderHsqldbFactoryMethodTest() {
-        super(
-                new JdbcRule(
-                        new AbstractConnectionSource() {
-                            @Override
-                            public Connection getConnection() throws SQLException {
-                                return JdbcAppenderHsqldbFactoryMethodTest.getConnection();
-                            }
-                        },
-                        "CREATE TABLE fmLogEntry ("
-                                + "id INTEGER IDENTITY, eventDate DATETIME, literalColumn VARCHAR(255), level VARCHAR(10), "
-                                + "logger VARCHAR(255), message VARCHAR(1024), exception CLOB, anotherDate TIMESTAMP"
-                                + ")",
-                        "DROP TABLE IF EXISTS fmLogEntry"),
-                "hsqldb");
+        super(new JdbcRule(
+                new AbstractConnectionSource() {
+                    @Override
+                    public Connection getConnection() throws SQLException {
+                        return JdbcAppenderHsqldbFactoryMethodTest.getConnection();
+                    }
+                },
+                "CREATE TABLE fmLogEntry ("
+                        + "id INTEGER IDENTITY, eventDate DATETIME, literalColumn VARCHAR(255), level VARCHAR(10), "
+                        + "logger VARCHAR(255), message VARCHAR(1024), exception CLOB, anotherDate TIMESTAMP"
+                        + ")",
+                "DROP TABLE IF EXISTS fmLogEntry"));
     }
 
     public static Connection getConnection() throws SQLException {
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderMapMessageDataSourceTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderMapMessageDataSourceTest.java
index 7923157b5e..b96593a875 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderMapMessageDataSourceTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderMapMessageDataSourceTest.java
@@ -16,8 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mock;
 
@@ -28,58 +29,49 @@ import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
 import javax.sql.DataSource;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
 import org.apache.logging.log4j.core.test.junit.JdbcRule;
-import org.apache.logging.log4j.core.test.junit.JndiRule;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.JndiExtension;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.core.util.Throwables;
 import org.apache.logging.log4j.message.MapMessage;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Unit tests {@link MapMessage}s for JdbcAppender using a {@link DataSource} configuration.
  */
 public class JdbcAppenderMapMessageDataSourceTest extends AbstractJdbcDataSourceTest {
 
-    @Rule
-    public final RuleChain rules;
+    @RegisterExtension
+    public final JndiExtension ext = new JndiExtension(createBindings());
 
-    private final JdbcRule jdbcRule;
+    @RegisterExtension
+    private final JdbcRule jdbcRule = new JdbcRule(
+            JdbcH2TestHelper.TEST_CONFIGURATION_SOURCE_MEM,
+            "CREATE TABLE dsLogEntry (Id INTEGER, ColumnA VARCHAR(255), ColumnB VARCHAR(255))",
+            "DROP TABLE IF EXISTS dsLogEntry");
 
-    public JdbcAppenderMapMessageDataSourceTest() {
-        this(new JdbcRule(
-                JdbcH2TestHelper.TEST_CONFIGURATION_SOURCE_MEM,
-                // @formatter:off
-                "CREATE TABLE dsLogEntry (Id INTEGER, ColumnA VARCHAR(255), ColumnB VARCHAR(255))",
-                "DROP TABLE IF EXISTS dsLogEntry"));
-        // @formatter:on
+    private Map<String, Object> createBindings() {
+        final Map<String, Object> map = new HashMap<>();
+        map.put("java:/comp/env/jdbc/TestDataSourceAppender", createMockDataSource());
+        return map;
     }
 
-    protected JdbcAppenderMapMessageDataSourceTest(final JdbcRule jdbcRule) {
-        // @formatter:off
-        this.rules = RuleChain.emptyRuleChain()
-                .around(new JndiRule("java:/comp/env/jdbc/TestDataSourceAppender", createMockDataSource()))
-                .around(jdbcRule)
-                .around(new LoggerContextRule(
-                        "org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source-map-message.xml"));
-        // @formatter:on
-        this.jdbcRule = jdbcRule;
-    }
-
-    @Before
+    @AfterEach
     public void afterEachDeleteDir() throws IOException {
         JdbcH2TestHelper.deleteDir();
     }
 
-    @Before
+    @BeforeEach
     public void beforeEachDeleteDir() throws IOException {
         JdbcH2TestHelper.deleteDir();
     }
@@ -97,6 +89,7 @@ public class JdbcAppenderMapMessageDataSourceTest extends AbstractJdbcDataSource
     }
 
     @Test
+    @LoggerContextSource("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source-map-message.xml")
     public void testDataSourceConfig() throws Exception {
         try (final Connection connection = jdbcRule.getConnectionSource().getConnection()) {
             final Error exception = new Error("Final error massage is fatal!");
@@ -116,16 +109,17 @@ public class JdbcAppenderMapMessageDataSourceTest extends AbstractJdbcDataSource
                     final ResultSet resultSet =
                             statement.executeQuery("SELECT Id, ColumnA, ColumnB FROM dsLogEntry ORDER BY Id")) {
 
-                assertTrue("There should be at least one row.", resultSet.next());
+                assertTrue(resultSet.next(), "There should be at least one row.");
 
-                Assert.assertEquals(1, resultSet.getInt("Id"));
+                assertEquals(1, resultSet.getInt("Id"));
 
-                assertFalse("There should not be two rows.", resultSet.next());
+                assertFalse(resultSet.next(), "There should not be two rows.");
             }
         }
     }
 
     @Test
+    @LoggerContextSource("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source-map-message.xml")
     public void testTruncate() throws SQLException {
         try (final Connection connection = jdbcRule.getConnectionSource().getConnection()) {
             final Logger logger = LogManager.getLogger(this.getClass().getName() + ".testFactoryMethodConfig");
@@ -140,11 +134,11 @@ public class JdbcAppenderMapMessageDataSourceTest extends AbstractJdbcDataSource
                     final ResultSet resultSet =
                             statement.executeQuery("SELECT Id, ColumnA, ColumnB FROM dsLogEntry ORDER BY Id")) {
 
-                assertTrue("There should be at least one row.", resultSet.next());
+                assertTrue(resultSet.next(), "There should be at least one row.");
 
-                Assert.assertEquals(1, resultSet.getInt("Id"));
+                assertEquals(1, resultSet.getInt("Id"));
 
-                assertFalse("There should not be two rows.", resultSet.next());
+                assertFalse(resultSet.next(), "There should not be two rows.");
             }
         }
     }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderStringSubstitutionTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderStringSubstitutionTest.java
index 693aa83579..8b0ca4bd73 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderStringSubstitutionTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderStringSubstitutionTest.java
@@ -16,11 +16,14 @@
  */
 package org.apache.logging.log4j.core.appender.db.jdbc;
 
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Named;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
 
 public class JdbcAppenderStringSubstitutionTest {
 
@@ -31,23 +34,19 @@ public class JdbcAppenderStringSubstitutionTest {
         System.setProperty(KEY, VALUE);
     }
 
-    @AfterClass
+    @AfterAll
     public static void afterClass() {
         System.getProperties().remove(KEY);
     }
 
-    @Rule
-    public final LoggerContextRule rule =
-            new LoggerContextRule("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-jdbc-string-substitution.xml");
-
     @Test
-    public void test() {
-        final JdbcAppender appender = rule.getAppender("databaseAppender", JdbcAppender.class);
-        Assert.assertNotNull(appender);
+    @LoggerContextSource("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-jdbc-string-substitution.xml")
+    public void test(@Named("databaseAppender") JdbcAppender appender) {
+        assertNotNull(appender);
         final JdbcDatabaseManager manager = appender.getManager();
-        Assert.assertNotNull(manager);
+        assertNotNull(manager);
         final String sqlStatement = manager.getSqlStatement();
-        Assert.assertFalse(sqlStatement, sqlStatement.contains(KEY));
-        Assert.assertTrue(sqlStatement, sqlStatement.contains(VALUE));
+        assertFalse(sqlStatement.contains(KEY), sqlStatement);
+        assertTrue(sqlStatement.contains(VALUE), sqlStatement);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java
index 5507c33075..a42058f3d5 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java
@@ -38,22 +38,21 @@ import javax.jms.Session;
 import javax.jms.TextMessage;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
-import org.apache.logging.log4j.core.test.categories.Appenders;
 import org.apache.logging.log4j.core.test.junit.JndiRule;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.message.StringMapMessage;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.RuleChain;
-
-@Category(Appenders.Jms.class)
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+@Tag("Appenders.Jms")
 public class JmsAppenderTest {
 
     private static final String CONNECTION_FACTORY_NAME = "jms/connectionFactory";
@@ -76,24 +75,23 @@ public class JmsAppenderTest {
     private final ObjectMessage objectMessage = mock(ObjectMessage.class);
     private final MapMessage mapMessage = mock(MapMessage.class);
 
+    @RegisterExtension
     private final JndiRule jndiRule = new JndiRule(createBindings());
-    private final LoggerContextRule ctx = new LoggerContextRule("JmsAppenderTest.xml");
 
-    @Rule
-    public RuleChain rules = RuleChain.outerRule(jndiRule).around(ctx);
+    private LoggerContext ctx = null;
 
-    @AfterClass
+    @AfterAll
     public static void afterClass() {
         System.clearProperty("log4j2.enableJndiJms");
     }
 
-    @BeforeClass
+    @BeforeAll
     public static void beforeClass() {
         System.setProperty("log4j2.enableJndiJms", "true");
     }
 
     public JmsAppenderTest() throws Exception {
-        // this needs to set up before LoggerContextRule
+        // this needs to set up before LoggerContext
         given(connectionFactory.createConnection()).willReturn(connection);
         given(connectionFactory.createConnection(anyString(), anyString())).willThrow(IllegalArgumentException.class);
         given(connection.createSession(eq(false), eq(Session.AUTO_ACKNOWLEDGE))).willReturn(session);
@@ -136,15 +134,16 @@ public class JmsAppenderTest {
         return createLogEvent(mapMessage.with("testMesage", LOG_MESSAGE));
     }
 
-    @Before
+    @BeforeEach
     public void setUp() throws Exception {
         // we have 4 appenders all connecting to the same ConnectionFactory
         then(connection).should(times(4)).start();
     }
 
     @Test
-    public void testAppendToQueue() throws Exception {
-        final JmsAppender appender = (JmsAppender) ctx.getRequiredAppender("JmsAppender");
+    @LoggerContextSource("JmsAppenderTest.xml")
+    public void testAppendToQueue(LoggerContext ctx) throws Exception {
+        final JmsAppender appender = (JmsAppender) ctx.getConfiguration().getAppender("JmsAppender");
         final LogEvent event = createLogEvent();
         appender.append(event);
         then(session).should().createTextMessage(eq(LOG_MESSAGE));
@@ -156,8 +155,9 @@ public class JmsAppenderTest {
     }
 
     @Test
-    public void testAppendToQueueWithMessageLayout() throws Exception {
-        final JmsAppender appender = (JmsAppender) ctx.getRequiredAppender("JmsAppender-MessageLayout");
+    @LoggerContextSource("JmsAppenderTest.xml")
+    public void testAppendToQueueWithMessageLayout(LoggerContext ctx) throws Exception {
+        final JmsAppender appender = (JmsAppender) ctx.getConfiguration().getAppender("JmsAppender-MessageLayout");
         final LogEvent event = createMapMessageLogEvent();
         appender.append(event);
         then(session).should().createMapMessage();
@@ -169,8 +169,9 @@ public class JmsAppenderTest {
     }
 
     @Test
-    public void testJmsQueueAppenderCompatibility() throws Exception {
-        final JmsAppender appender = (JmsAppender) ctx.getRequiredAppender("JmsQueueAppender");
+    @LoggerContextSource("JmsAppenderTest.xml")
+    public void testJmsQueueAppenderCompatibility(LoggerContext ctx) throws Exception {
+        final JmsAppender appender = (JmsAppender) ctx.getConfiguration().getAppender("JmsQueueAppender");
         final LogEvent expected = createLogEvent();
         appender.append(expected);
         then(session).should().createObjectMessage(eq(expected));
@@ -182,8 +183,9 @@ public class JmsAppenderTest {
     }
 
     @Test
-    public void testJmsTopicAppenderCompatibility() throws Exception {
-        final JmsAppender appender = (JmsAppender) ctx.getRequiredAppender("JmsTopicAppender");
+    @LoggerContextSource("JmsAppenderTest.xml")
+    public void testJmsTopicAppenderCompatibility(LoggerContext ctx) throws Exception {
+        final JmsAppender appender = (JmsAppender) ctx.getConfiguration().getAppender("JmsTopicAppender");
         final LogEvent expected = createLogEvent();
         appender.append(expected);
         then(session).should().createObjectMessage(eq(expected));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java
index 3a54a91d0a..87c54fc291 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java
@@ -16,21 +16,24 @@
  */
 package org.apache.logging.log4j.core.appender.mom.kafka;
 
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
 import java.time.Duration;
 import java.util.concurrent.TimeUnit;
 import org.apache.kafka.clients.producer.MockProducer;
 import org.apache.kafka.common.serialization.ByteArraySerializer;
 import org.apache.kafka.common.serialization.Serializer;
 import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.test.categories.Appenders;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Named;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
 
-@Category(Appenders.Kafka.class)
+@Tag("Appenders.Kafka")
+@LoggerContextSource("KafkaAppenderCloseTimeoutTest.xml")
 public class KafkaAppenderCloseTimeoutTest {
 
     private static final Serializer<byte[]> SERIALIZER = new ByteArraySerializer();
@@ -65,22 +68,20 @@ public class KafkaAppenderCloseTimeoutTest {
                 }
             };
 
-    @BeforeClass
-    public static void setUpClass() {
+    @BeforeAll
+    public static void setUpAll() {
         KafkaManager.producerFactory = config -> kafka;
     }
 
-    @Rule
-    public LoggerContextRule ctx = new LoggerContextRule("KafkaAppenderCloseTimeoutTest.xml");
-
-    @Before
+    @BeforeEach
     public void setUp() {
         kafka.clear();
     }
 
-    @Test(timeout = 2000)
-    public void testClose() {
-        final Appender appender = ctx.getRequiredAppender("KafkaAppender");
+    @Test
+    @Timeout(2000)
+    public void testClose(@Named("KafkaAppender") final Appender appender) {
+        assertNotNull(appender, "Appender named KafkaAppender was null.");
         appender.stop();
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java
index b265126cd2..156341ab55 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java
@@ -16,12 +16,12 @@
  */
 package org.apache.logging.log4j.core.appender.mom.kafka;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
 
 import java.nio.charset.StandardCharsets;
 import java.text.SimpleDateFormat;
@@ -45,17 +45,16 @@ import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.ErrorHandler;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
-import org.apache.logging.log4j.core.test.categories.Appenders;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Named;
 import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.test.junit.SerialUtil;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
 
-@Category(Appenders.Kafka.class)
+@Tag("Appenders.Kafka")
 public class KafkaAppenderTest {
 
     private static final Serializer<byte[]> SERIALIZER = new ByteArraySerializer();
@@ -108,22 +107,20 @@ public class KafkaAppenderTest {
                 .build();
     }
 
-    @BeforeClass
-    public static void setUpClass() {
+    @BeforeAll
+    public static void setUpAll() {
         KafkaManager.producerFactory = config -> kafka;
     }
 
-    @Rule
-    public LoggerContextRule ctx = new LoggerContextRule("KafkaAppenderTest.xml");
-
-    @Before
+    @BeforeEach
     public void setUp() {
         kafka.clear();
     }
 
     @Test
-    public void testAppendWithLayout() {
-        final Appender appender = ctx.getRequiredAppender("KafkaAppenderWithLayout");
+    @LoggerContextSource("KafkaAppenderTest.xml")
+    public void testAppendWithLayout(@Named("KafkaAppenderWithLayout") final Appender appender) {
+        assertNotNull(appender, "Appender named KafkaAppenderWithLayout was null.");
         appender.append(createLogEvent());
         final List<ProducerRecord<byte[], byte[]>> history = kafka.history();
         assertEquals(1, history.size());
@@ -135,8 +132,9 @@ public class KafkaAppenderTest {
     }
 
     @Test
-    public void testAppendWithSerializedLayout() {
-        final Appender appender = ctx.getRequiredAppender("KafkaAppenderWithSerializedLayout");
+    @LoggerContextSource("KafkaAppenderTest.xml")
+    public void testAppendWithSerializedLayout(@Named("KafkaAppenderWithSerializedLayout") final Appender appender) {
+        assertNotNull(appender, "Appender named KafkaAppenderWithSerializedLayout was null.");
         final LogEvent logEvent = createLogEvent();
         appender.append(logEvent);
         final List<ProducerRecord<byte[], byte[]>> history = kafka.history();
@@ -151,8 +149,9 @@ public class KafkaAppenderTest {
     }
 
     @Test
-    public void testAsyncAppend() {
-        final Appender appender = ctx.getRequiredAppender("AsyncKafkaAppender");
+    @LoggerContextSource("KafkaAppenderTest.xml")
+    public void testAsyncAppend(@Named("AsyncKafkaAppender") final Appender appender) {
+        assertNotNull(appender, "Appender named AsyncKafkaAppender was null.");
         appender.append(createLogEvent());
         final List<ProducerRecord<byte[], byte[]>> history = kafka.history();
         assertEquals(1, history.size());
@@ -164,8 +163,9 @@ public class KafkaAppenderTest {
     }
 
     @Test
-    public void testAppendWithKey() {
-        final Appender appender = ctx.getRequiredAppender("KafkaAppenderWithKey");
+    @LoggerContextSource("KafkaAppenderTest.xml")
+    public void testAppendWithKey(@Named("KafkaAppenderWithKey") final Appender appender) {
+        assertNotNull(appender, "Appender named KafkaAppenderWithKey was null.");
         final LogEvent logEvent = createLogEvent();
         appender.append(logEvent);
         final List<ProducerRecord<byte[], byte[]>> history = kafka.history();
@@ -180,8 +180,9 @@ public class KafkaAppenderTest {
     }
 
     @Test
-    public void testAppendWithKeyLookup() {
-        final Appender appender = ctx.getRequiredAppender("KafkaAppenderWithKeyLookup");
+    @LoggerContextSource("KafkaAppenderTest.xml")
+    public void testAppendWithKeyLookup(@Named("KafkaAppenderWithKeyLookup") final Appender appender) {
+        assertNotNull(appender, "Appender named KafkaAppenderWithKeyLookup was null.");
         final LogEvent logEvent = createLogEvent();
         final Date date = new Date();
         final SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
@@ -198,10 +199,11 @@ public class KafkaAppenderTest {
     }
 
     @Test
-    public void testAppendWithRetryCount() {
+    @LoggerContextSource("KafkaAppenderTest.xml")
+    public void testAppendWithRetryCount(@Named("KafkaAppenderWithRetryCount") final Appender appender) {
+        assertNotNull(appender, "Appender named KafkaAppenderWithRetryCount was null.");
         try {
             ThreadContext.put("KafkaAppenderWithRetryCount", "true");
-            final Appender appender = ctx.getRequiredAppender("KafkaAppenderWithRetryCount");
             final LogEvent logEvent = createLogEvent();
             appender.append(logEvent);
 
@@ -215,10 +217,11 @@ public class KafkaAppenderTest {
     }
 
     @Test
-    public void testRetrySuccessDoesNotReportError() {
+    @LoggerContextSource("KafkaAppenderTest.xml")
+    public void testRetrySuccessDoesNotReportError(@Named("KafkaAppenderWithRetryCount") final Appender appender) {
+        assertNotNull(appender, "Appender named KafkaAppenderWithRetryCount was null.");
         retrySendCount.set(0);
         final AtomicBoolean errorReported = new AtomicBoolean(false);
-        final Appender appender = ctx.getRequiredAppender("KafkaAppenderWithRetryCount");
         final ErrorHandler originalHandler = ((KafkaAppender) appender).getHandler();
         try (final CloseableThreadContext.Instance ignored =
                 CloseableThreadContext.put("KafkaAppenderRetrySuccessTest", "true")) {
@@ -241,15 +244,16 @@ public class KafkaAppenderTest {
             appender.append(createLogEvent());
             final List<ProducerRecord<byte[], byte[]>> history = kafka.history();
             assertEquals(2, history.size());
-            assertFalse("Error should not be reported when retry succeeds", errorReported.get());
+            assertFalse(errorReported.get(), "Error should not be reported when retry succeeds");
         } finally {
             ((KafkaAppender) appender).setHandler(originalHandler);
         }
     }
 
     @Test
-    public void testAppenderNoEventTimestamp() {
-        final Appender appender = ctx.getRequiredAppender("KafkaAppenderNoEventTimestamp");
+    @LoggerContextSource("KafkaAppenderTest.xml")
+    public void testAppenderNoEventTimestamp(@Named("KafkaAppenderNoEventTimestamp") final Appender appender) {
+        assertNotNull(appender, "Appender named KafkaAppenderNoEventTimestamp was null.");
         final LogEvent logEvent = createLogEvent();
         appender.append(logEvent);
         final List<ProducerRecord<byte[], byte[]>> history = kafka.history();
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java
index d53769e8b8..4bd4b4d5c7 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java
@@ -16,10 +16,11 @@
  */
 package org.apache.logging.log4j.core.appender.nosql;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.BDDMockito.then;
@@ -41,18 +42,20 @@ import org.apache.logging.log4j.core.appender.AppenderLoggingException;
 import org.apache.logging.log4j.core.impl.ContextDataFactory;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.test.junit.ThreadContextStackRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
+import org.apache.logging.log4j.test.junit.UsingAnyThreadContext;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
 
-@RunWith(MockitoJUnitRunner.class)
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+@UsingAnyThreadContext
 public class NoSqlDatabaseManagerTest {
 
     @Mock
@@ -67,13 +70,7 @@ public class NoSqlDatabaseManagerTest {
     @Captor
     private ArgumentCaptor<NoSqlObject<Map<String, Object>>> captor;
 
-    @Rule
-    public final ThreadContextStackRule threadContextRule = new ThreadContextStackRule();
-
-    @Rule
-    public final ExpectedException expectedException = ExpectedException.none();
-
-    @Before
+    @BeforeEach
     public void setUp() {
         given(provider.getConnection()).willReturn(connection);
         given(connection.createObject()).willAnswer(invocation -> new DefaultNoSqlObject());
@@ -86,7 +83,7 @@ public class NoSqlDatabaseManagerTest {
         try (final NoSqlDatabaseManager<?> manager =
                 NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, provider, null, null)) {
 
-            assertNotNull("The manager should not be null.", manager);
+            assertNotNull(manager, "The manager should not be null.");
 
             manager.connectAndStart();
             then(provider).should().getConnection();
@@ -98,8 +95,7 @@ public class NoSqlDatabaseManagerTest {
     public void testWriteInternalNotConnected01() {
         try (final NoSqlDatabaseManager<?> manager =
                 NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, provider, null, null)) {
-            expectedException.expect(AppenderLoggingException.class);
-            manager.writeInternal(mock(LogEvent.class), null);
+            assertThrows(AppenderLoggingException.class, () -> manager.writeInternal(mock(LogEvent.class), null));
         }
     }
 
@@ -114,8 +110,7 @@ public class NoSqlDatabaseManagerTest {
             manager.connectAndStart();
             then(provider).should().getConnection();
 
-            expectedException.expect(AppenderLoggingException.class);
-            manager.writeInternal(mock(LogEvent.class), null);
+            assertThrows(AppenderLoggingException.class, () -> manager.writeInternal(mock(LogEvent.class), null));
         }
     }
 
@@ -146,33 +141,33 @@ public class NoSqlDatabaseManagerTest {
             then(connection).should().insertObject(captor.capture());
 
             final NoSqlObject<Map<String, Object>> inserted = captor.getValue();
-            assertNotNull("The inserted value should not be null.", inserted);
+            assertNotNull(inserted, "The inserted value should not be null.");
             final Map<String, Object> object = inserted.unwrap();
-            assertNotNull("The unwrapped object should not be null.", object);
+            assertNotNull(object, "The unwrapped object should not be null.");
 
-            assertEquals("The level is not correct.", Level.WARN, object.get("level"));
+            assertEquals(Level.WARN, object.get("level"), "The level is not correct.");
             assertEquals(
-                    "The logger is not correct.", "com.foo.NoSQLDbTest.testWriteInternal01", object.get("loggerName"));
-            assertEquals("The message is not correct.", "My formatted message 01.", object.get("message"));
-            assertEquals("The thread is not correct.", "MyThread-A", object.get("threadName"));
-            assertEquals("The millis is not correct.", 1234567890123L, object.get("millis"));
-            assertEquals("The date is not correct.", 1234567890123L, ((Date) object.get("date")).getTime());
+                    "com.foo.NoSQLDbTest.testWriteInternal01", object.get("loggerName"), "The logger is not correct.");
+            assertEquals("My formatted message 01.", object.get("message"), "The message is not correct.");
+            assertEquals("MyThread-A", object.get("threadName"), "The thread is not correct.");
+            assertEquals(1234567890123L, object.get("millis"), "The millis is not correct.");
+            assertEquals(1234567890123L, ((Date) object.get("date")).getTime(), "The date is not correct.");
 
-            assertTrue("The source should be a map.", object.get("source") instanceof Map);
+            assertTrue(object.get("source") instanceof Map, "The source should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> source = (Map<String, Object>) object.get("source");
-            assertEquals("The class is not correct.", "com.foo.Bar", source.get("className"));
-            assertEquals("The method is not correct.", "testMethod01", source.get("methodName"));
-            assertEquals("The file name is not correct.", "Bar.java", source.get("fileName"));
-            assertEquals("The line number is not correct.", 15, source.get("lineNumber"));
+            assertEquals("com.foo.Bar", source.get("className"), "The class is not correct.");
+            assertEquals("testMethod01", source.get("methodName"), "The method is not correct.");
+            assertEquals("Bar.java", source.get("fileName"), "The file name is not correct.");
+            assertEquals(15, source.get("lineNumber"), "The line number is not correct.");
 
-            assertNull("The marker should be null.", object.get("marker"));
+            assertNull(object.get("marker"), "The marker should be null.");
 
-            assertNull("The thrown should be null.", object.get("thrown"));
+            assertNull(object.get("thrown"), "The thrown should be null.");
 
-            assertTrue("The context map should be empty.", ((Map) object.get("contextMap")).isEmpty());
+            assertTrue(((Map) object.get("contextMap")).isEmpty(), "The context map should be empty.");
 
-            assertTrue("The context stack should be null.", ((Collection) object.get("contextStack")).isEmpty());
+            assertTrue(((Collection) object.get("contextStack")).isEmpty(), "The context stack should be null.");
         }
     }
 
@@ -217,62 +212,62 @@ public class NoSqlDatabaseManagerTest {
             then(connection).should().insertObject(captor.capture());
 
             final NoSqlObject<Map<String, Object>> inserted = captor.getValue();
-            assertNotNull("The inserted value should not be null.", inserted);
+            assertNotNull(inserted, "The inserted value should not be null.");
             final Map<String, Object> object = inserted.unwrap();
-            assertNotNull("The unwrapped object should not be null.", object);
+            assertNotNull(object, "The unwrapped object should not be null.");
 
-            assertEquals("The level is not correct.", Level.DEBUG, object.get("level"));
+            assertEquals(Level.DEBUG, object.get("level"), "The level is not correct.");
             assertEquals(
-                    "The logger is not correct.", "com.foo.NoSQLDbTest.testWriteInternal02", object.get("loggerName"));
-            assertEquals("The message is not correct.", "Another cool message 02.", object.get("message"));
-            assertEquals("The thread is not correct.", "AnotherThread-B", object.get("threadName"));
-            assertEquals("The millis is not correct.", 987654321564L, object.get("millis"));
-            assertEquals("The date is not correct.", 987654321564L, ((Date) object.get("date")).getTime());
+                    "com.foo.NoSQLDbTest.testWriteInternal02", object.get("loggerName"), "The logger is not correct.");
+            assertEquals("Another cool message 02.", object.get("message"), "The message is not correct.");
+            assertEquals("AnotherThread-B", object.get("threadName"), "The thread is not correct.");
+            assertEquals(987654321564L, object.get("millis"), "The millis is not correct.");
+            assertEquals(987654321564L, ((Date) object.get("date")).getTime(), "The date is not correct.");
 
-            assertTrue("The source should be a map.", object.get("source") instanceof Map);
+            assertTrue(object.get("source") instanceof Map, "The source should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> source = (Map<String, Object>) object.get("source");
-            assertEquals("The class is not correct.", "com.bar.Foo", source.get("className"));
-            assertEquals("The method is not correct.", "anotherMethod03", source.get("methodName"));
-            assertEquals("The file name is not correct.", "Foo.java", source.get("fileName"));
-            assertEquals("The line number is not correct.", 9, source.get("lineNumber"));
+            assertEquals("com.bar.Foo", source.get("className"), "The class is not correct.");
+            assertEquals("anotherMethod03", source.get("methodName"), "The method is not correct.");
+            assertEquals("Foo.java", source.get("fileName"), "The file name is not correct.");
+            assertEquals(9, source.get("lineNumber"), "The line number is not correct.");
 
-            assertTrue("The marker should be a map.", object.get("marker") instanceof Map);
+            assertTrue(object.get("marker") instanceof Map, "The marker should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> marker = (Map<String, Object>) object.get("marker");
-            assertEquals("The marker name is not correct.", "LoneMarker", marker.get("name"));
-            assertNull("The marker parent should be null.", marker.get("parent"));
+            assertEquals("LoneMarker", marker.get("name"), "The marker name is not correct.");
+            assertNull(marker.get("parent"), "The marker parent should be null.");
 
-            assertTrue("The thrown should be a map.", object.get("thrown") instanceof Map);
+            assertTrue(object.get("thrown") instanceof Map, "The thrown should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> thrown = (Map<String, Object>) object.get("thrown");
-            assertEquals("The thrown type is not correct.", "java.lang.RuntimeException", thrown.get("type"));
-            assertEquals("The thrown message is not correct.", "This is something cool!", thrown.get("message"));
-            assertTrue("The thrown stack trace should be a list.", thrown.get("stackTrace") instanceof List);
+            assertEquals("java.lang.RuntimeException", thrown.get("type"), "The thrown type is not correct.");
+            assertEquals("This is something cool!", thrown.get("message"), "The thrown message is not correct.");
+            assertTrue(thrown.get("stackTrace") instanceof List, "The thrown stack trace should be a list.");
             @SuppressWarnings("unchecked")
             final List<Map<String, Object>> stackTrace = (List<Map<String, Object>>) thrown.get("stackTrace");
             assertEquals(
-                    "The thrown stack trace length is not correct.",
                     exception.getStackTrace().length,
-                    stackTrace.size());
+                    stackTrace.size(),
+                    "The thrown stack trace length is not correct.");
             for (int i = 0; i < exception.getStackTrace().length; i++) {
                 final StackTraceElement e1 = exception.getStackTrace()[i];
                 final Map<String, Object> e2 = stackTrace.get(i);
 
-                assertEquals("Element class name [" + i + "] is not correct.", e1.getClassName(), e2.get("className"));
+                assertEquals(e1.getClassName(), e2.get("className"), "Element class name [" + i + "] is not correct.");
                 assertEquals(
-                        "Element method name [" + i + "] is not correct.", e1.getMethodName(), e2.get("methodName"));
-                assertEquals("Element file name [" + i + "] is not correct.", e1.getFileName(), e2.get("fileName"));
+                        e1.getMethodName(), e2.get("methodName"), "Element method name [" + i + "] is not correct.");
+                assertEquals(e1.getFileName(), e2.get("fileName"), "Element file name [" + i + "] is not correct.");
                 assertEquals(
-                        "Element line number [" + i + "] is not correct.", e1.getLineNumber(), e2.get("lineNumber"));
+                        e1.getLineNumber(), e2.get("lineNumber"), "Element line number [" + i + "] is not correct.");
             }
-            assertNull("The thrown should have no cause.", thrown.get("cause"));
+            assertNull(thrown.get("cause"), "The thrown should have no cause.");
 
-            assertTrue("The context map should be a map.", object.get("contextMap") instanceof Map);
-            assertEquals("The context map is not correct.", context, object.get("contextMap"));
+            assertTrue(object.get("contextMap") instanceof Map, "The context map should be a map.");
+            assertEquals(context, object.get("contextMap"), "The context map is not correct.");
 
-            assertTrue("The context stack should be list.", object.get("contextStack") instanceof List);
-            assertEquals("The context stack is not correct.", stack.asList(), object.get("contextStack"));
+            assertTrue(object.get("contextStack") instanceof List, "The context stack should be list.");
+            assertEquals(stack.asList(), object.get("contextStack"), "The context stack is not correct.");
         }
     }
 
@@ -322,111 +317,111 @@ public class NoSqlDatabaseManagerTest {
             then(connection).should().insertObject(captor.capture());
 
             final NoSqlObject<Map<String, Object>> inserted = captor.getValue();
-            assertNotNull("The inserted value should not be null.", inserted);
+            assertNotNull(inserted, "The inserted value should not be null.");
             final Map<String, Object> object = inserted.unwrap();
-            assertNotNull("The unwrapped object should not be null.", object);
+            assertNotNull(object, "The unwrapped object should not be null.");
 
-            assertEquals("The level is not correct.", Level.DEBUG, object.get("level"));
+            assertEquals(Level.DEBUG, object.get("level"), "The level is not correct.");
             assertEquals(
-                    "The logger is not correct.", "com.foo.NoSQLDbTest.testWriteInternal02", object.get("loggerName"));
-            assertEquals("The message is not correct.", "Another cool message 02.", object.get("message"));
-            assertEquals("The thread is not correct.", "AnotherThread-B", object.get("threadName"));
-            assertEquals("The millis is not correct.", 987654321564L, object.get("millis"));
-            assertEquals("The date is not correct.", 987654321564L, ((Date) object.get("date")).getTime());
+                    "com.foo.NoSQLDbTest.testWriteInternal02", object.get("loggerName"), "The logger is not correct.");
+            assertEquals("Another cool message 02.", object.get("message"), "The message is not correct.");
+            assertEquals("AnotherThread-B", object.get("threadName"), "The thread is not correct.");
+            assertEquals(987654321564L, object.get("millis"), "The millis is not correct.");
+            assertEquals(987654321564L, ((Date) object.get("date")).getTime(), "The date is not correct.");
 
-            assertTrue("The source should be a map.", object.get("source") instanceof Map);
+            assertTrue(object.get("source") instanceof Map, "The source should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> source = (Map<String, Object>) object.get("source");
-            assertEquals("The class is not correct.", "com.bar.Foo", source.get("className"));
-            assertEquals("The method is not correct.", "anotherMethod03", source.get("methodName"));
-            assertEquals("The file name is not correct.", "Foo.java", source.get("fileName"));
-            assertEquals("The line number is not correct.", 9, source.get("lineNumber"));
+            assertEquals("com.bar.Foo", source.get("className"), "The class is not correct.");
+            assertEquals("anotherMethod03", source.get("methodName"), "The method is not correct.");
+            assertEquals("Foo.java", source.get("fileName"), "The file name is not correct.");
+            assertEquals(9, source.get("lineNumber"), "The line number is not correct.");
 
-            assertTrue("The marker should be a map.", object.get("marker") instanceof Map);
+            assertTrue(object.get("marker") instanceof Map, "The marker should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> marker = (Map<String, Object>) object.get("marker");
-            assertEquals("The marker name is not correct.", "AnotherMarker", marker.get("name"));
+            assertEquals("AnotherMarker", marker.get("name"), "The marker name is not correct.");
 
-            assertTrue("The marker parents should be a list.", marker.get("parents") instanceof List);
+            assertTrue(marker.get("parents") instanceof List, "The marker parents should be a list.");
             @SuppressWarnings("unchecked")
             final List<Object> markerParents = (List<Object>) marker.get("parents");
-            assertEquals("The marker parents should contain two parents", 2, markerParents.size());
+            assertEquals(2, markerParents.size(), "The marker parents should contain two parents");
 
-            assertTrue("The marker parents[0] should be a map.", markerParents.get(0) instanceof Map);
+            assertTrue(markerParents.get(0) instanceof Map, "The marker parents[0] should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> parent1 = (Map<String, Object>) markerParents.get(0);
-            assertEquals("The first marker parent name is not correct.", "Parent1", parent1.get("name"));
+            assertEquals("Parent1", parent1.get("name"), "The first marker parent name is not correct.");
 
-            assertTrue("The marker parents[1] should be a map.", markerParents.get(1) instanceof Map);
+            assertTrue(markerParents.get(1) instanceof Map, "The marker parents[1] should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> parent2 = (Map<String, Object>) markerParents.get(1);
-            assertEquals("The second marker parent name is not correct.", "Parent2", parent2.get("name"));
-            assertNull("The second marker should have no parent.", parent2.get("parent"));
+            assertEquals("Parent2", parent2.get("name"), "The second marker parent name is not correct.");
+            assertNull(parent2.get("parent"), "The second marker should have no parent.");
 
-            assertTrue("The parent1 parents should be a list.", parent1.get("parents") instanceof List);
+            assertTrue(parent1.get("parents") instanceof List, "The parent1 parents should be a list.");
             @SuppressWarnings("unchecked")
             final List<Object> parent1Parents = (List<Object>) parent1.get("parents");
-            assertEquals("The parent1 parents should have only one parent", 1, parent1Parents.size());
+            assertEquals(1, parent1Parents.size(), "The parent1 parents should have only one parent");
 
-            assertTrue("The parent1Parents[0] should be a map.", parent1Parents.get(0) instanceof Map);
+            assertTrue(parent1Parents.get(0) instanceof Map, "The parent1Parents[0] should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> parent1parent = (Map<String, Object>) parent1Parents.get(0);
-            assertEquals("The first parent1 parent name is not correct.", "GrandParent1", parent1parent.get("name"));
-            assertNull("The parent1parent marker should have no parent.", parent1parent.get("parent"));
+            assertEquals("GrandParent1", parent1parent.get("name"), "The first parent1 parent name is not correct.");
+            assertNull(parent1parent.get("parent"), "The parent1parent marker should have no parent.");
 
-            assertTrue("The thrown should be a map.", object.get("thrown") instanceof Map);
+            assertTrue(object.get("thrown") instanceof Map, "The thrown should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> thrown = (Map<String, Object>) object.get("thrown");
-            assertEquals("The thrown type is not correct.", "java.sql.SQLException", thrown.get("type"));
-            assertEquals("The thrown message is not correct.", "This is the result.", thrown.get("message"));
-            assertTrue("The thrown stack trace should be a list.", thrown.get("stackTrace") instanceof List);
+            assertEquals("java.sql.SQLException", thrown.get("type"), "The thrown type is not correct.");
+            assertEquals("This is the result.", thrown.get("message"), "The thrown message is not correct.");
+            assertTrue(thrown.get("stackTrace") instanceof List, "The thrown stack trace should be a list.");
             @SuppressWarnings("unchecked")
             final List<Map<String, Object>> stackTrace = (List<Map<String, Object>>) thrown.get("stackTrace");
             assertEquals(
-                    "The thrown stack trace length is not correct.",
                     exception2.getStackTrace().length,
-                    stackTrace.size());
+                    stackTrace.size(),
+                    "The thrown stack trace length is not correct.");
             for (int i = 0; i < exception2.getStackTrace().length; i++) {
                 final StackTraceElement e1 = exception2.getStackTrace()[i];
                 final Map<String, Object> e2 = stackTrace.get(i);
 
-                assertEquals("Element class name [" + i + "] is not correct.", e1.getClassName(), e2.get("className"));
+                assertEquals(e1.getClassName(), e2.get("className"), "Element class name [" + i + "] is not correct.");
                 assertEquals(
-                        "Element method name [" + i + "] is not correct.", e1.getMethodName(), e2.get("methodName"));
-                assertEquals("Element file name [" + i + "] is not correct.", e1.getFileName(), e2.get("fileName"));
+                        e1.getMethodName(), e2.get("methodName"), "Element method name [" + i + "] is not correct.");
+                assertEquals(e1.getFileName(), e2.get("fileName"), "Element file name [" + i + "] is not correct.");
                 assertEquals(
-                        "Element line number [" + i + "] is not correct.", e1.getLineNumber(), e2.get("lineNumber"));
+                        e1.getLineNumber(), e2.get("lineNumber"), "Element line number [" + i + "] is not correct.");
             }
-            assertTrue("The thrown cause should be a map.", thrown.get("cause") instanceof Map);
+            assertTrue(thrown.get("cause") instanceof Map, "The thrown cause should be a map.");
             @SuppressWarnings("unchecked")
             final Map<String, Object> cause = (Map<String, Object>) thrown.get("cause");
-            assertEquals("The cause type is not correct.", "java.io.IOException", cause.get("type"));
-            assertEquals("The cause message is not correct.", "This is the cause.", cause.get("message"));
-            assertTrue("The cause stack trace should be a list.", cause.get("stackTrace") instanceof List);
+            assertEquals("java.io.IOException", cause.get("type"), "The cause type is not correct.");
+            assertEquals("This is the cause.", cause.get("message"), "The cause message is not correct.");
+            assertTrue(cause.get("stackTrace") instanceof List, "The cause stack trace should be a list.");
             @SuppressWarnings("unchecked")
             final List<Map<String, Object>> causeStackTrace = (List<Map<String, Object>>) cause.get("stackTrace");
             assertEquals(
-                    "The cause stack trace length is not correct.",
                     exception1.getStackTrace().length,
-                    causeStackTrace.size());
+                    causeStackTrace.size(),
+                    "The cause stack trace length is not correct.");
             for (int i = 0; i < exception1.getStackTrace().length; i++) {
                 final StackTraceElement e1 = exception1.getStackTrace()[i];
                 final Map<String, Object> e2 = causeStackTrace.get(i);
 
-                assertEquals("Element class name [" + i + "] is not correct.", e1.getClassName(), e2.get("className"));
+                assertEquals(e1.getClassName(), e2.get("className"), "Element class name [" + i + "] is not correct.");
                 assertEquals(
-                        "Element method name [" + i + "] is not correct.", e1.getMethodName(), e2.get("methodName"));
-                assertEquals("Element file name [" + i + "] is not correct.", e1.getFileName(), e2.get("fileName"));
+                        e1.getMethodName(), e2.get("methodName"), "Element method name [" + i + "] is not correct.");
+                assertEquals(e1.getFileName(), e2.get("fileName"), "Element file name [" + i + "] is not correct.");
                 assertEquals(
-                        "Element line number [" + i + "] is not correct.", e1.getLineNumber(), e2.get("lineNumber"));
+                        e1.getLineNumber(), e2.get("lineNumber"), "Element line number [" + i + "] is not correct.");
             }
-            assertNull("The cause should have no cause.", cause.get("cause"));
+            assertNull(cause.get("cause"), "The cause should have no cause.");
 
-            assertTrue("The context map should be a map.", object.get("contextMap") instanceof Map);
-            assertEquals("The context map is not correct.", context, object.get("contextMap"));
+            assertTrue(object.get("contextMap") instanceof Map, "The context map should be a map.");
+            assertEquals(context, object.get("contextMap"), "The context map is not correct.");
 
-            assertTrue("The context stack should be list.", object.get("contextStack") instanceof List);
-            assertEquals("The context stack is not correct.", stack.asList(), object.get("contextStack"));
+            assertTrue(object.get("contextStack") instanceof List, "The context stack should be list.");
+            assertEquals(stack.asList(), object.get("contextStack"), "The context stack is not correct.");
         }
     }
 
@@ -450,7 +445,7 @@ public class NoSqlDatabaseManagerTest {
             assertEquals(exception.getMessage(), thrown.get("message"));
             assertEquals(exception.getCause().getMessage(), cause.get("message"));
             assertEquals(exception.getCause().getCause().getMessage(), nestedCause.get("message"));
-            assertNull("The cycle should not be serialized.", nestedCause.get("cause"));
+            assertNull(nestedCause.get("cause"), "The cycle should not be serialized.");
         }
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RandomRollingAppenderOnStartupTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RandomRollingAppenderOnStartupTest.java
index 6ed7c13e94..3c4295986f 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RandomRollingAppenderOnStartupTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RandomRollingAppenderOnStartupTest.java
@@ -16,57 +16,29 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.Collection;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
 
 /**
  *
  */
-@RunWith(Parameterized.class)
+@LoggerContextSource
 public class RandomRollingAppenderOnStartupTest {
 
     private static final String DIR = "target/onStartup";
 
-    private Logger logger;
-
-    @Parameterized.Parameters(name = "{0} \u2192 {1}")
-    public static Collection<Object[]> data() {
-        return Arrays.asList(new Object[][] { //
-            // @formatter:off
-            {"log4j-test5.xml"}, {"log4j-test5.xml"},
-        });
-        // @formatter:on
-    }
-
-    @Rule
-    public LoggerContextRule loggerContextRule;
-
-    public RandomRollingAppenderOnStartupTest(final String configFile) {
-        this.loggerContextRule = LoggerContextRule.createShutdownTimeoutLoggerContextRule(configFile);
-    }
-
-    @Before
-    public void setUp() {
-        this.logger = this.loggerContextRule.getLogger(RandomRollingAppenderOnStartupTest.class.getName());
-    }
-
-    @BeforeClass
-    public static void beforeClass() throws Exception {
+    @BeforeAll
+    public static void beforeAll() throws Exception {
         if (Files.exists(Paths.get("target/onStartup"))) {
             try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(DIR))) {
                 for (final Path path : directoryStream) {
@@ -77,28 +49,33 @@ public class RandomRollingAppenderOnStartupTest {
         }
     }
 
-    @AfterClass
-    public static void afterClass() throws Exception {
+    @AfterAll
+    public static void afterAll() throws Exception {
         long size = 0;
-        try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(DIR))) {
-            for (final Path path : directoryStream) {
-                if (size == 0) {
-                    size = Files.size(path);
-                } else {
-                    final long fileSize = Files.size(path);
-                    assertEquals(
-                            "Expected size: " + size + " Size of " + path.getFileName() + ": " + fileSize,
-                            size,
-                            fileSize);
+        if (Files.exists(Paths.get(DIR))) {
+            try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(DIR))) {
+                for (final Path path : directoryStream) {
+                    if (size == 0) {
+                        size = Files.size(path);
+                    } else {
+                        final long fileSize = Files.size(path);
+                        assertEquals(
+                                size,
+                                fileSize,
+                                "Expected size: " + size + " Size of " + path.getFileName() + ": " + fileSize);
+                    }
+                    Files.delete(path);
                 }
-                Files.delete(path);
+                Files.delete(Paths.get(DIR));
             }
-            Files.delete(Paths.get(DIR));
         }
     }
 
     @Test
-    public void testAppender() {
+    @LoggerContextSource("log4j-test5.xml")
+    public void testAppender(final LoggerContext loggerContext) {
+        Logger logger = loggerContext.getLogger(RandomRollingAppenderOnStartupTest.class.getName());
+
         for (int i = 0; i < 100; ++i) {
             logger.debug("This is test message number " + i);
         }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCountTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCountTest.java
index e8bd5a9e8a..cb12324f5f 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCountTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCountTest.java
@@ -16,7 +16,7 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.io.File;
 import java.nio.file.DirectoryStream;
@@ -27,41 +27,32 @@ import java.nio.file.StandardCopyOption;
 import java.util.Objects;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
 
 /**
  * Validate rolling with a file pattern that contains leading zeros for the increment.
  */
-@Ignore("https://issues.apache.org/jira/browse/LOG4J2-3522")
+@Disabled("https://issues.apache.org/jira/browse/LOG4J2-3522")
+@LoggerContextSource("log4j-rolling-count.xml")
 public class RollingAppenderCountTest {
 
     private static final String SOURCE = "src/test/resources/__files";
     private static final String DIR = "target/rolling_count";
-    private static final String CONFIG = "log4j-rolling-count.xml";
     private static final String FILENAME = "onStartup.log";
     private static final String TARGET = "rolling_test.log.";
 
     private Logger logger;
 
-    @Rule
-    public LoggerContextRule loggerContextRule;
-
-    public RollingAppenderCountTest() {
-        this.loggerContextRule = LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-    }
-
-    @Before
-    public void setUp() {
-        this.logger = this.loggerContextRule.getLogger("LogTest");
+    public RollingAppenderCountTest(LoggerContext context) {
+        this.logger = context.getLogger("LogTest");
     }
 
-    @BeforeClass
+    @BeforeAll
     public static void beforeClass() throws Exception {
         if (Files.exists(Paths.get(DIR))) {
             try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(DIR))) {
@@ -79,10 +70,10 @@ public class RollingAppenderCountTest {
         Files.copy(Paths.get(SOURCE, FILENAME), target, StandardCopyOption.COPY_ATTRIBUTES);
     }
 
-    @AfterClass
+    @AfterAll
     public static void afterClass() throws Exception {
         final int count = Objects.requireNonNull(new File(DIR).listFiles()).length;
-        assertEquals("Expected 17 files, got " + count, 17, count);
+        assertEquals(17, count, "Expected 17 files, got " + count);
         try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(DIR))) {
             for (final Path path : directoryStream) {
                 Files.delete(path);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeLookupTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeLookupTest.java
index 509cf83122..98a7d5da61 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeLookupTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeLookupTest.java
@@ -21,19 +21,19 @@ import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.Arrays;
 import java.util.Random;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * LOG4J2-1804.
@@ -44,17 +44,18 @@ public class RollingAppenderCronAndSizeLookupTest {
 
     private static final String DIR = "target/rolling-cron-size-lookup";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private Logger logger;
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingAppenderCronAndSizeLookupTest.class.getName());
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingAppenderCronAndSizeLookupTest.class.getName());
     }
 
     @Test
@@ -69,7 +70,7 @@ public class RollingAppenderCronAndSizeLookupTest {
         }
         Thread.sleep(50);
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
         final File[] files = dir.listFiles();
         Arrays.sort(files);
         assertNotNull(files);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeTest.java
index 973ae70a85..80ee7c5cdc 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronAndSizeTest.java
@@ -21,19 +21,19 @@ import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.Arrays;
 import java.util.Random;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * LOG4J2-1804.
@@ -41,20 +41,20 @@ import org.junit.rules.RuleChain;
 public class RollingAppenderCronAndSizeTest {
 
     private static final String CONFIG = "log4j-rolling-cron-and-size.xml";
-
     private static final String DIR = "target/rolling-cron-size";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
-
     private Logger logger;
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingAppenderCronAndSizeTest.class.getName());
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
+
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingAppenderCronAndSizeTest.class.getName());
     }
 
     @Test
@@ -69,7 +69,7 @@ public class RollingAppenderCronAndSizeTest {
         }
         Thread.sleep(50);
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
         final File[] files = dir.listFiles();
         Arrays.sort(files);
         assertNotNull(files);
@@ -88,9 +88,9 @@ public class RollingAppenderCronAndSizeTest {
             fileCounter = previous.equals(fileParts[1]) ? ++fileCounter : 1;
             previous = fileParts[1];
             assertEquals(
-                    "Incorrect file name. Expected counter value of " + fileCounter + " in " + actual,
                     Integer.toString(fileCounter),
-                    fileParts[2]);
+                    fileParts[2],
+                    "Incorrect file name. Expected counter value of " + fileCounter + " in " + actual);
         }
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2DirectTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2DirectTest.java
index c75f06bc46..7cbb313b6f 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2DirectTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2DirectTest.java
@@ -20,18 +20,18 @@ import static org.apache.logging.log4j.core.test.hamcrest.Descriptors.that;
 import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.security.SecureRandom;
 import java.util.Random;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.hamcrest.Matcher;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -42,16 +42,17 @@ public class RollingAppenderCronEvery2DirectTest {
     private static final String DIR = "target/rolling-cron-every2Direct";
     private static final int LOOP_COUNT = 100;
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
         // TODO Is there a better way to test than putting the thread to sleep all over the place?
-        final Logger logger = loggerContextRule.getLogger();
+        final Logger logger = loggerContext.getLogger(RollingAppenderCronEvery2DirectTest.class.getName());
         final long end = System.currentTimeMillis() + 5000;
         final Random rand = new SecureRandom();
         rand.setSeed(end);
@@ -61,7 +62,7 @@ public class RollingAppenderCronEvery2DirectTest {
             Thread.sleep(10 * rand.nextInt(100));
         } while (System.currentTimeMillis() < end);
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
 
         final int MAX_TRIES = 20;
         final Matcher<File[]> hasGzippedFile = hasItemInArray(that(hasName(that(endsWith(".gz")))));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2Test.java
index 9145448d1d..43da56f65e 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronEvery2Test.java
@@ -20,18 +20,18 @@ import static org.apache.logging.log4j.core.test.hamcrest.Descriptors.that;
 import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.security.SecureRandom;
 import java.util.Random;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.hamcrest.Matcher;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -43,18 +43,19 @@ public class RollingAppenderCronEvery2Test {
     private static final String FILE = "target/rolling-cron-every2/rollingtest.log";
     private static final int LOOP_COUNT = 100;
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
         // TODO Is there a better way to test than putting the thread to sleep all over the place?
-        final Logger logger = loggerContextRule.getLogger();
+        final Logger logger = loggerContext.getLogger(RollingAppenderCronEvery2Test.class.getName());
         final File file = new File(FILE);
-        assertTrue("Log file does not exist", file.exists());
+        assertTrue(file.exists(), "Log file does not exist");
         final long end = System.currentTimeMillis() + 5000;
         final Random rand = new SecureRandom();
         rand.setSeed(end);
@@ -64,7 +65,7 @@ public class RollingAppenderCronEvery2Test {
             Thread.sleep(10 * rand.nextInt(100));
         } while (System.currentTimeMillis() < end);
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
 
         final int MAX_TRIES = 20;
         final Matcher<File[]> hasGzippedFile = hasItemInArray(that(hasName(that(endsWith(".gz")))));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnceADayTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnceADayTest.java
index bab06818ac..19303e90f9 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnceADayTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronOnceADayTest.java
@@ -19,10 +19,10 @@ package org.apache.logging.log4j.core.appender.rolling;
 import static org.apache.logging.log4j.core.test.hamcrest.Descriptors.that;
 import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.Matchers.endsWith;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.nio.charset.StandardCharsets;
@@ -31,15 +31,15 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Calendar;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.RollingFileAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.apache.logging.log4j.core.util.CronExpression;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.hamcrest.Matcher;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * This test currently takes about a minute to run.
@@ -58,8 +58,8 @@ public class RollingAppenderCronOnceADayTest {
     private static String cronExpression;
     private static long remainingTime;
 
-    @BeforeClass
-    public static void beforeClass() throws Exception {
+    @BeforeAll
+    public static void beforeAll() throws Exception {
         final Path src = FileSystems.getDefault().getPath(TARGET_TEST_CLASSES, CONFIG);
         String content = new String(Files.readAllBytes(src), StandardCharsets.UTF_8);
         final Calendar cal = Calendar.getInstance();
@@ -74,26 +74,28 @@ public class RollingAppenderCronOnceADayTest {
         StatusLogger.getLogger().debug("Cron expression will be " + cronExpression + " in " + remainingTime + "ms");
     }
 
-    private final LoggerContextRule loggerContextRule = new LoggerContextRule(CONFIG_TARGET);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG_TARGET,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
         // TODO Is there a better way to test than putting the thread to sleep all over the place?
-        final Logger logger = loggerContextRule.getLogger();
+        final Logger logger = loggerContext.getLogger(RollingAppenderCronOnceADayTest.class.getName());
         final File file = new File(FILE);
-        assertTrue("Log file does not exist", file.exists());
+        assertTrue(file.exists(), "Log file does not exist");
         logger.debug("This is test message number 1, waiting for rolling");
 
         final RollingFileAppender app =
-                loggerContextRule.getLoggerContext().getConfiguration().getAppender("RollingFile");
+                (RollingFileAppender) loggerContext.getConfiguration().getAppender("RollingFile");
         final TriggeringPolicy policy = app.getManager().getTriggeringPolicy();
-        assertNotNull("No triggering policy", policy);
-        assertTrue("Incorrect policy type", policy instanceof CronTriggeringPolicy);
+        assertNotNull(policy, "No triggering policy");
+        assertTrue(policy instanceof CronTriggeringPolicy, "Incorrect policy type");
         final CronExpression expression = ((CronTriggeringPolicy) policy).getCronExpression();
-        assertEquals("Incorrect cron expresion", cronExpression, expression.getCronExpression());
+        assertEquals(cronExpression, expression.getCronExpression(), "Incorrect cron expression");
         logger.debug("Cron expression will be {}", expression.getCronExpression());
 
         // force a reconfiguration
@@ -103,7 +105,7 @@ public class RollingAppenderCronOnceADayTest {
 
         Thread.sleep(remainingTime);
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
 
         for (int i = 1; i < 5; i++) {
             logger.debug("Adding some more event {}", i);
@@ -118,7 +120,7 @@ public class RollingAppenderCronOnceADayTest {
             }
         }
 
-        assertNotEquals("No compressed files found", 0, count);
-        assertEquals("Multiple files found", 1, count);
+        assertNotEquals(0, count, "No compressed files found");
+        assertEquals(1, count, "Multiple files found");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java
index 0130de1e48..3f6215fd11 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java
@@ -20,10 +20,10 @@ import static org.apache.logging.log4j.core.test.hamcrest.Descriptors.that;
 import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -32,13 +32,13 @@ import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.RollingFileAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.apache.logging.log4j.core.util.CronExpression;
 import org.hamcrest.Matcher;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -49,22 +49,23 @@ public class RollingAppenderCronTest {
     private static final String DIR = "target/rolling-cron";
     private static final String FILE = "target/rolling-cron/rollingtest.log";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
         // TODO Is there a better way to test than putting the thread to sleep all over the place?
-        final Logger logger = loggerContextRule.getLogger();
+        final Logger logger = loggerContext.getLogger(RollingAppenderCronTest.class.getName());
         final File file = new File(FILE);
-        assertTrue("Log file does not exist", file.exists());
+        assertTrue(file.exists(), "Log file does not exist");
         logger.debug("This is test message number 1");
         Thread.sleep(2500);
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
 
         final int MAX_TRIES = 20;
         final Matcher<File[]> hasGzippedFile = hasItemInArray(that(hasName(that(endsWith(".gz")))));
@@ -96,11 +97,11 @@ public class RollingAppenderCronTest {
         }
         Thread.sleep(1000);
         final RollingFileAppender app =
-                loggerContextRule.getLoggerContext().getConfiguration().getAppender("RollingFile");
+                (RollingFileAppender) loggerContext.getConfiguration().getAppender("RollingFile");
         final TriggeringPolicy policy = app.getManager().getTriggeringPolicy();
-        assertNotNull("No triggering policy", policy);
-        assertTrue("Incorrect policy type", policy instanceof CronTriggeringPolicy);
+        assertNotNull(policy, "No triggering policy");
+        assertTrue(policy instanceof CronTriggeringPolicy, "Incorrect policy type");
         final CronExpression expression = ((CronTriggeringPolicy) policy).getCronExpression();
-        assertEquals("Incorrect triggering policy", "* * * ? * *", expression.getCronExpression());
+        assertEquals("* * * ? * *", expression.getCronExpression(), "Incorrect triggering policy");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCustomDeleteActionTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCustomDeleteActionTest.java
index a5a015f35b..e896bb42ee 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCustomDeleteActionTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCustomDeleteActionTest.java
@@ -16,17 +16,17 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.util.Arrays;
 import java.util.regex.Pattern;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -36,15 +36,16 @@ public class RollingAppenderCustomDeleteActionTest {
     private static final String CONFIG = "log4j-rolling-with-custom-delete.xml";
     private static final String DIR = "target/rolling-with-delete/test";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
-        final Logger logger = loggerContextRule.getLogger();
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
+        final Logger logger = loggerContext.getLogger(RollingAppenderCustomDeleteActionTest.class.getName());
         // Trigger the rollover
         for (int i = 0; i < 10; ++i) {
             // 30 chars per message: each message triggers a rollover
@@ -53,8 +54,8 @@ public class RollingAppenderCustomDeleteActionTest {
         Thread.sleep(100); // Allow time for rollover to complete
 
         final File dir = new File(DIR);
-        assertTrue("Dir " + DIR + " should exist", dir.exists());
-        assertTrue("Dir " + DIR + " should contain files", dir.listFiles().length > 0);
+        assertTrue(dir.exists(), "Dir " + DIR + " should exist");
+        assertTrue(dir.listFiles().length > 0, "Dir " + DIR + " should contain files");
 
         final int MAX_TRIES = 20;
         for (int i = 0; i < MAX_TRIES; i++) {
@@ -65,9 +66,9 @@ public class RollingAppenderCustomDeleteActionTest {
             if (files.length == 3) {
                 for (final File file : files) {
                     assertTrue(
-                            "test-4.log should have been deleted",
                             Arrays.asList("test-1.log", "test-2.log", "test-3.log")
-                                    .contains(file.getName()));
+                                    .contains(file.getName()),
+                            "test-4.log should have been deleted");
                 }
                 return; // test succeeded
             }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount1Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount1Test.java
index b901713423..01aef6f0af 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount1Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount1Test.java
@@ -17,8 +17,8 @@
 package org.apache.logging.log4j.core.appender.rolling;
 
 import static org.awaitility.Awaitility.waitAtMost;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -33,10 +33,10 @@ import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Tests that sibling conditions are invoked in configured order.
@@ -46,21 +46,22 @@ public class RollingAppenderDeleteAccumulatedCount1Test {
     private static final String CONFIG = "log4j-rolling-with-custom-delete-accum-count1.xml";
     private static final String DIR = "target/rolling-with-delete-accum-count1/test";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
         final Path p1 = writeTextTo(DIR + "/my-1.log"); // glob="test-*.log"
         final Path p2 = writeTextTo(DIR + "/my-2.log");
         final Path p3 = writeTextTo(DIR + "/my-3.log");
         final Path p4 = writeTextTo(DIR + "/my-4.log");
         final Path p5 = writeTextTo(DIR + "/my-5.log");
 
-        final Logger logger = loggerContextRule.getLogger();
+        final Logger logger = loggerContext.getLogger(RollingAppenderDeleteAccumulatedCount1Test.class.getName());
         for (int i = 0; i < 10; ++i) {
             updateLastModified(p1, p2, p3, p4, p5); // make my-*.log files most recent
 
@@ -69,17 +70,17 @@ public class RollingAppenderDeleteAccumulatedCount1Test {
         }
 
         final File dir = new File(DIR);
-        assertTrue("Dir " + DIR + " should exist", dir.exists());
+        assertTrue(dir.exists(), "Dir " + DIR + " should exist");
 
         final List<String> expected = Arrays.asList("my-1.log", "my-2.log", "my-3.log", "my-4.log", "my-5.log");
 
         waitAtMost(7, TimeUnit.SECONDS).untilAsserted(() -> {
             final File[] files = Objects.requireNonNull(dir.listFiles(), "listFiles()");
-            assertTrue("Dir " + DIR + " should contain files", files.length > 0);
+            assertTrue(files.length > 0, "Dir " + DIR + " should contain files");
 
             // The 5 my-*.log files must exist
             for (final String name : expected) {
-                assertTrue("missing " + name, new File(dir, name).exists());
+                assertTrue(new File(dir, name).exists(), "missing " + name);
             }
 
             // Only allow my-*.log and test-*.log
@@ -97,7 +98,7 @@ public class RollingAppenderDeleteAccumulatedCount1Test {
                     .count();
 
             // Tolerate CRLF/LF differences + timing jitter
-            assertTrue("expected rolled count in [6, 9], got " + rolled, rolled >= 6 && rolled <= 9);
+            assertTrue(rolled >= 6 && rolled <= 9, "expected rolled count in [6, 9], got " + rolled);
         });
     }
 
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount2Test.java
index 8329c6ef51..67b3b19e59 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount2Test.java
@@ -16,9 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -31,12 +31,12 @@ import java.nio.file.attribute.FileTime;
 import java.util.Arrays;
 import java.util.List;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Tests that sibling conditions are invoked in configured order.
@@ -46,21 +46,22 @@ public class RollingAppenderDeleteAccumulatedCount2Test {
     private static final String CONFIG = "log4j-rolling-with-custom-delete-accum-count2.xml";
     private static final String DIR = "target/rolling-with-delete-accum-count2/test";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
         final Path p1 = writeTextTo(DIR + "/my-1.log"); // glob="test-*.log"
         final Path p2 = writeTextTo(DIR + "/my-2.log");
         final Path p3 = writeTextTo(DIR + "/my-3.log");
         final Path p4 = writeTextTo(DIR + "/my-4.log");
         final Path p5 = writeTextTo(DIR + "/my-5.log");
 
-        final Logger logger = loggerContextRule.getLogger();
+        final Logger logger = loggerContext.getLogger(RollingAppenderDeleteAccumulatedCount2Test.class.getName());
         for (int i = 0; i < 10; ++i) {
             updateLastModified(p1, p2, p3, p4, p5); // make my-*.log files most recent
 
@@ -70,8 +71,8 @@ public class RollingAppenderDeleteAccumulatedCount2Test {
         Thread.sleep(100); // Allow time for rollover to complete
 
         final File dir = new File(DIR);
-        assertTrue("Dir " + DIR + " should exist", dir.exists());
-        assertTrue("Dir " + DIR + " should contain files", dir.listFiles().length > 0);
+        assertTrue(dir.exists(), "Dir " + DIR + " should exist");
+        assertTrue(dir.listFiles().length > 0, "Dir " + DIR + " should contain files");
 
         final File[] files = dir.listFiles();
         for (final File file : files) {
@@ -80,7 +81,7 @@ public class RollingAppenderDeleteAccumulatedCount2Test {
         }
         // sometimes "test-9.log", sometimes "test-10.log" remains
         final List<String> expected = Arrays.asList("my-1.log", "my-2.log", "my-3.log", "my-4.log", "my-5.log");
-        assertEquals(Arrays.toString(files), expected.size() + 1, files.length);
+        assertEquals(expected.size() + 1, files.length, Arrays.toString(files));
         for (final File file : files) {
             if (!expected.contains(file.getName()) && !file.getName().startsWith("test-")) {
                 fail("unexpected file" + file);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedSizeTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedSizeTest.java
index 5e36333f56..7989855427 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedSizeTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedSizeTest.java
@@ -16,18 +16,18 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.Arrays;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -36,16 +36,17 @@ public class RollingAppenderDeleteAccumulatedSizeTest {
     private static final String CONFIG = "log4j-rolling-with-custom-delete-accum-size.xml";
     private static final String DIR = "target/rolling-with-delete-accum-size/test";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
 
-        final Logger logger = loggerContextRule.getLogger();
+        final Logger logger = loggerContext.getLogger(RollingAppenderDeleteAccumulatedSizeTest.class.getName());
         for (int i = 0; i < 10; ++i) {
             // 30 chars per message: each message triggers a rollover
             logger.debug("This is a test message number " + i); // 30 chars:
@@ -53,21 +54,21 @@ public class RollingAppenderDeleteAccumulatedSizeTest {
         Thread.sleep(100); // Allow time for rollover to complete
 
         final File dir = new File(DIR);
-        assertTrue("Dir " + DIR + " should exist", dir.exists());
-        assertTrue("Dir " + DIR + " should contain files", dir.listFiles().length > 0);
+        assertTrue(dir.exists(), "Dir " + DIR + " should exist");
+        assertTrue(dir.listFiles().length > 0, "Dir " + DIR + " should contain files");
 
         final File[] files = dir.listFiles();
         for (final File file : files) {
             System.out.println(file + " (" + file.length() + "B) "
                     + FixedDateFormat.create(FixedFormat.ABSOLUTE).format(file.lastModified()));
         }
-        assertEquals(Arrays.toString(files), 4, files.length);
+        assertEquals(4, files.length, Arrays.toString(files));
         long total = 0;
         for (final File file : files) {
             // sometimes test-6.log remains
-            assertTrue("unexpected file " + file, file.getName().startsWith("test-"));
+            assertTrue(file.getName().startsWith("test-"), "unexpected file " + file);
             total += file.length();
         }
-        assertTrue("accumulatedSize=" + total, total <= 500);
+        assertTrue(total <= 500, "accumulatedSize=" + total);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteMaxDepthTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteMaxDepthTest.java
index f51a7c9e2b..29520af6ec 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteMaxDepthTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteMaxDepthTest.java
@@ -16,8 +16,8 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -30,10 +30,10 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.regex.Pattern;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -43,21 +43,22 @@ public class RollingAppenderDeleteMaxDepthTest {
     private static final String CONFIG = "log4j-rolling-with-custom-delete-maxdepth.xml";
     private static final String DIR = "target/rolling-with-delete-depth/test";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
         // create some files that match the glob but exceed maxDepth
         final Path p1 = writeTextTo(DIR + "/1/test-4.log"); // glob="**/test-4.log"
         final Path p2 = writeTextTo(DIR + "/2/test-4.log");
         final Path p3 = writeTextTo(DIR + "/1/2/test-4.log");
         final Path p4 = writeTextTo(DIR + "/1/2/3/test-4.log");
 
-        final Logger logger = loggerContextRule.getLogger();
+        final Logger logger = loggerContext.getLogger(RollingAppenderDeleteMaxDepthTest.class.getName());
         for (int i = 0; i < 10; ++i) {
             // 30 chars per message: each message triggers a rollover
             logger.debug("This is a test message number " + i); // 30 chars:
@@ -65,20 +66,20 @@ public class RollingAppenderDeleteMaxDepthTest {
         Thread.sleep(100); // Allow time for rollover to complete
 
         final File dir = new File(DIR);
-        assertTrue("Dir " + DIR + " should exist", dir.exists());
-        assertTrue("Dir " + DIR + " should contain files", dir.listFiles().length > 0);
+        assertTrue(dir.exists(), "Dir " + DIR + " should exist");
+        assertTrue(dir.listFiles().length > 0, "Dir " + DIR + " should contain files");
 
         final File[] files = dir.listFiles();
         final List<String> expected = Arrays.asList("1", "2", "test-1.log", "test-2.log", "test-3.log");
-        assertEquals(Arrays.toString(files), expected.size(), files.length);
+        assertEquals(expected.size(), files.length, Arrays.toString(files));
         for (final File file : files) {
-            assertTrue("test-4.log should have been deleted", expected.contains(file.getName()));
+            assertTrue(expected.contains(file.getName()), "test-4.log should have been deleted");
         }
 
-        assertTrue(p1 + " should not have been deleted", Files.exists(p1));
-        assertTrue(p2 + " should not have been deleted", Files.exists(p2));
-        assertTrue(p3 + " should not have been deleted", Files.exists(p3));
-        assertTrue(p4 + " should not have been deleted", Files.exists(p4));
+        assertTrue(Files.exists(p1), p1 + " should not have been deleted");
+        assertTrue(Files.exists(p2), p2 + " should not have been deleted");
+        assertTrue(Files.exists(p3), p3 + " should not have been deleted");
+        assertTrue(Files.exists(p4), p4 + " should not have been deleted");
     }
 
     private Path writeTextTo(final String location) throws IOException {
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteNestedTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteNestedTest.java
index c9691087ff..00feac65df 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteNestedTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteNestedTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -31,12 +31,12 @@ import java.nio.file.attribute.FileTime;
 import java.util.Arrays;
 import java.util.List;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -45,21 +45,22 @@ public class RollingAppenderDeleteNestedTest {
     private static final String CONFIG = "log4j-rolling-with-custom-delete-nested.xml";
     private static final String DIR = "target/rolling-with-delete-nested/test";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
         final Path p1 = writeTextTo(DIR + "/my-1.log"); // glob="test-*.log"
         final Path p2 = writeTextTo(DIR + "/my-2.log");
         final Path p3 = writeTextTo(DIR + "/my-3.log");
         final Path p4 = writeTextTo(DIR + "/my-4.log");
         final Path p5 = writeTextTo(DIR + "/my-5.log");
 
-        final Logger logger = loggerContextRule.getLogger();
+        final Logger logger = loggerContext.getLogger(RollingAppenderDeleteNestedTest.class.getName());
         for (int i = 0; i < 10; ++i) {
             updateLastModified(p1, p2, p3, p4, p5); // make my-*.log files most recent
 
@@ -69,8 +70,8 @@ public class RollingAppenderDeleteNestedTest {
         Thread.sleep(100); // Allow time for rollover to complete
 
         final File dir = new File(DIR);
-        assertTrue("Dir " + DIR + " should exist", dir.exists());
-        assertTrue("Dir " + DIR + " should contain files", dir.listFiles().length > 0);
+        assertTrue(dir.exists(), "Dir " + DIR + " should exist");
+        assertTrue(dir.listFiles().length > 0, "Dir " + DIR + " should contain files");
 
         final File[] files = dir.listFiles();
         for (final File file : files) {
@@ -79,7 +80,7 @@ public class RollingAppenderDeleteNestedTest {
         }
 
         final List<String> expected = Arrays.asList("my-1.log", "my-2.log", "my-3.log", "my-4.log", "my-5.log");
-        assertEquals(Arrays.toString(files), expected.size() + 3, files.length);
+        assertEquals(expected.size() + 3, files.length, Arrays.toString(files));
         for (final File file : files) {
             if (!expected.contains(file.getName()) && !file.getName().startsWith("test-")) {
                 fail("unexpected file" + file);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteScriptFri13thTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteScriptFri13thTest.java
index 49210e73ae..e60321cd97 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteScriptFri13thTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteScriptFri13thTest.java
@@ -16,40 +16,41 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
 
 import java.io.File;
 import java.time.DayOfWeek;
 import java.time.LocalDate;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.apache.logging.log4j.core.util.Constants;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class RollingAppenderDeleteScriptFri13thTest {
 
     private static final String CONFIG = "log4j-rolling-with-custom-delete-script-fri13th.xml";
     private static final String DIR = "target/rolling-with-delete-script-fri13th/test";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @BeforeClass
-    public static void beforeClass() {
+    @BeforeAll
+    public static void beforeAll() {
         System.setProperty(Constants.SCRIPT_LANGUAGES, "Groovy, Javascript");
     }
 
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
         LocalDate now = LocalDate.now();
         // Ignore on Friday 13th
         assumeFalse(now.getDayOfWeek() == DayOfWeek.FRIDAY && now.getDayOfMonth() == 13);
@@ -59,9 +60,9 @@ public class RollingAppenderDeleteScriptFri13thTest {
             final String day = i < 10 ? "0" + i : "" + i;
             new File(dir, "test-201511" + day + "-0.log").createNewFile();
         }
-        assertEquals("Dir " + DIR + " filecount", 30, dir.listFiles().length);
+        assertEquals(30, dir.listFiles().length, "Dir " + DIR + " filecount");
 
-        final Logger logger = loggerContextRule.getLogger();
+        final Logger logger = loggerContext.getLogger(RollingAppenderDeleteScriptFri13thTest.class.getName());
         // Trigger the rollover
         while (dir.listFiles().length < 32) {
             // 60+ chars per message: each message should trigger a rollover
@@ -74,10 +75,10 @@ public class RollingAppenderDeleteScriptFri13thTest {
             System.out.println(file);
         }
         for (final File file : files) {
-            assertTrue(file.getName() + " starts with 'test-'", file.getName().startsWith("test-"));
-            assertTrue(file.getName() + " ends with '.log'", file.getName().endsWith(".log"));
+            assertTrue(file.getName().startsWith("test-"), file.getName() + " starts with 'test-'");
+            assertTrue(file.getName().endsWith(".log"), file.getName() + " ends with '.log'");
             final String strDate = file.getName().substring(5, 13);
-            assertFalse(file + " is not Fri 13th", strDate.endsWith("20151113"));
+            assertFalse(strDate.endsWith("20151113"), file + " is not Fri 13th");
         }
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteScriptTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteScriptTest.java
index c65c2114b3..9d983131fc 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteScriptTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteScriptTest.java
@@ -16,18 +16,18 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.apache.logging.log4j.core.util.Constants;
 import org.apache.logging.log4j.core.util.Integers;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -37,20 +37,21 @@ public class RollingAppenderDeleteScriptTest {
     private static final String CONFIG = "log4j-rolling-with-custom-delete-script.xml";
     private static final String DIR = "target/rolling-with-delete-script/test";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @BeforeClass
-    public static void beforeClass() {
+    @BeforeAll
+    public static void beforeAll() {
         System.setProperty(Constants.SCRIPT_LANGUAGES, "Groovy, Javascript");
     }
 
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
-        final Logger logger = loggerContextRule.getLogger();
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
+        final Logger logger = loggerContext.getLogger(RollingAppenderDeleteScriptTest.class.getName());
         // Trigger the rollover
         for (int i = 0; i < 10; ++i) {
             // 30 chars per message: each message triggers a rollover
@@ -59,19 +60,19 @@ public class RollingAppenderDeleteScriptTest {
         Thread.sleep(100); // Allow time for rollover to complete
 
         final File dir = new File(DIR);
-        assertTrue("Dir " + DIR + " should exist", dir.exists());
-        assertTrue("Dir " + DIR + " should contain files", dir.listFiles().length > 0);
+        assertTrue(dir.exists(), "Dir " + DIR + " should exist");
+        assertTrue(dir.listFiles().length > 0, "Dir " + DIR + " should contain files");
 
         final File[] files = dir.listFiles();
         for (final File file : files) {
             System.out.println(file);
         }
         for (final File file : files) {
-            assertTrue(file.getName() + " starts with 'test-'", file.getName().startsWith("test-"));
-            assertTrue(file.getName() + " ends with '.log'", file.getName().endsWith(".log"));
+            assertTrue(file.getName().startsWith("test-"), file.getName() + " starts with 'test-'");
+            assertTrue(file.getName().endsWith(".log"), file.getName() + " ends with '.log'");
             final String strIndex = file.getName().substring(5, file.getName().indexOf('.'));
             final int index = Integers.parseInt(strIndex);
-            assertEquals(file + " should have odd index", 1, index % 2);
+            assertEquals(1, index % 2, file + " should have odd index");
         }
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectCustomDeleteActionTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectCustomDeleteActionTest.java
index 4c812d4daf..270c6149ad 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectCustomDeleteActionTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectCustomDeleteActionTest.java
@@ -16,19 +16,19 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.Arrays;
 import java.util.regex.Pattern;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.RollingFileAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -38,18 +38,19 @@ public class RollingAppenderDirectCustomDeleteActionTest implements RolloverList
     private static final String CONFIG = "log4j-rolling-direct-with-custom-delete.xml";
     private static final String DIR = "target/rolling-direct-with-delete/test";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDirectCustomDeleteActionTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private boolean fileFound = false;
 
     @Test
-    public void testAppender() throws Exception {
-        final Logger logger = loggerContextRule.getLogger();
-        final RollingFileAppender app = loggerContextRule.getAppender("RollingFile");
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
+        final Logger logger = loggerContext.getLogger(RollingAppenderDirectCustomDeleteActionTest.class.getName());
+        final RollingFileAppender app = loggerContext.getConfiguration().getAppender("RollingFile");
         assertNotNull(app, "No RollingFileAppender");
         app.getManager().addRolloverListener(this);
         // Trigger the rollover
@@ -60,8 +61,8 @@ public class RollingAppenderDirectCustomDeleteActionTest implements RolloverList
         Thread.sleep(100); // Allow time for rollover to complete
 
         final File dir = new File(DIR);
-        assertTrue("Dir " + DIR + " should exist", dir.exists());
-        assertTrue("Dir " + DIR + " should contain files", dir.listFiles().length > 0);
+        assertTrue(dir.exists(), "Dir " + DIR + " should exist");
+        assertTrue(dir.listFiles().length > 0, "Dir " + DIR + " should contain files");
 
         final File[] files = dir.listFiles();
         assertNotNull(files, "No fiels");
@@ -69,8 +70,8 @@ public class RollingAppenderDirectCustomDeleteActionTest implements RolloverList
         final long count = Arrays.stream(files)
                 .filter((f) -> f.getName().endsWith("test-4.log"))
                 .count();
-        assertTrue("Deleted file was not created", fileFound);
-        assertEquals("File count expected: 0, actual: " + count, 0, count);
+        assertTrue(fileFound, "Deleted file was not created");
+        assertEquals(0, count, "File count expected: 0, actual: " + count);
     }
 
     public static void main(final String[] args) {
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWrite1906Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWrite1906Test.java
index dab76cab14..ea48b80436 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWrite1906Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWrite1906Test.java
@@ -21,9 +21,9 @@ import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -31,15 +31,15 @@ import java.io.FileReader;
 import java.util.List;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.apache.logging.log4j.status.StatusData;
 import org.apache.logging.log4j.status.StatusListener;
 import org.apache.logging.log4j.status.StatusLogger;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -47,25 +47,25 @@ import org.junit.rules.RuleChain;
 public class RollingAppenderDirectWrite1906Test {
 
     private static final String CONFIG = "log4j-rolling-direct-1906.xml";
-
     private static final String DIR = "target/rolling-direct-1906";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
-
     private Logger logger;
 
-    @BeforeClass
+    @BeforeAll
     public static void setupClass() {
         StatusLogger.getLogger().registerListener(new NoopStatusListener());
     }
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingAppenderDirectWrite1906Test.class.getName());
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
+
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingAppenderDirectWrite1906Test.class.getName());
     }
 
     @Test
@@ -77,7 +77,7 @@ public class RollingAppenderDirectWrite1906Test {
         }
         Thread.sleep(50);
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
         final File[] files = dir.listFiles();
         assertNotNull(files);
         assertThat(files, hasItemInArray(that(hasName(that(endsWith(".log"))))));
@@ -91,12 +91,12 @@ public class RollingAppenderDirectWrite1906Test {
                 final String[] parts = line.split((" "));
                 final String expected = "rollingfile." + parts[0] + ".log";
 
-                assertEquals(logFileNameError(expected, actual), expected, actual);
+                assertEquals(expected, actual, logFileNameError(expected, actual));
                 ++found;
             }
             reader.close();
         }
-        assertEquals("Incorrect number of events read. Expected " + count + ", Actual " + found, count, found);
+        assertEquals(count, found, "Incorrect number of events read. Expected " + count + ", Actual " + found);
     }
 
     private String logFileNameError(final String expected, final String actual) {
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteStartupSizeTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteStartupSizeTest.java
index 47ab9404ef..5e60c20fa0 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteStartupSizeTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteStartupSizeTest.java
@@ -16,16 +16,19 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import org.apache.logging.log4j.core.appender.RollingFileAppender;
-import org.apache.logging.log4j.core.test.junit.CleanFolders;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Named;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Test LOG4J2-2485.
@@ -40,14 +43,18 @@ public class RollingAppenderDirectWriteStartupSizeTest {
 
     private static final String MESSAGE = "test message";
 
-    @Rule
-    public LoggerContextRule loggerContextRule = LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public CleanFolders cleanFolders = new CleanFolders(false, true, 10, DIR);
+    @RegisterExtension
+    private CleanFoldersRuleExtension cleanFolders = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDirectWriteStartupSizeTest.class.getName(),
+            this.getClass().getClassLoader(),
+            false,
+            true,
+            10);
 
-    @BeforeClass
-    public static void beforeClass() throws Exception {
+    @BeforeAll
+    public static void beforeAll() throws Exception {
         final Path log = Paths.get(DIR, FILE);
         if (Files.exists(log)) {
             Files.delete(log);
@@ -59,12 +66,11 @@ public class RollingAppenderDirectWriteStartupSizeTest {
     }
 
     @Test
-    public void testRollingFileAppenderWithReconfigure() {
-        final RollingFileAppender rfAppender =
-                loggerContextRule.getRequiredAppender("RollingFile", RollingFileAppender.class);
+    @LoggerContextSource(value = CONFIG, timeout = 10)
+    public void testRollingFileAppenderWithReconfigure(@Named("RollingFile") RollingFileAppender rfAppender) {
         final RollingFileManager manager = rfAppender.getManager();
 
-        Assert.assertNotNull(manager);
-        Assert.assertEquals("Existing file size not preserved on startup", MESSAGE.getBytes().length, manager.size);
+        assertNotNull(manager);
+        assertEquals(MESSAGE.getBytes().length, manager.size, "Existing file size not preserved on startup");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithFilenameTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithFilenameTest.java
index 530c65c1fb..625d2e6498 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithFilenameTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithFilenameTest.java
@@ -16,15 +16,15 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 
 import java.io.File;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -32,25 +32,25 @@ import org.junit.rules.RuleChain;
 public class RollingAppenderDirectWriteWithFilenameTest {
 
     private static final String CONFIG = "log4j2-rolling-1833.xml";
-
     private static final String DIR = "target/rolling-1833";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
-
     private Logger logger;
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingAppenderDirectWriteWithFilenameTest.class.getName());
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
+
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingAppenderDirectWriteWithFilenameTest.class.getName());
     }
 
     @Test
-    public void testAppender() {
+    public void testAppender(LoggerContext context) {
         final File dir = new File(DIR);
-        assertFalse("Directory created", dir.exists());
+        assertFalse(dir.exists(), "Directory created");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java
index 82d3c118ee..386c44ab26 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java
@@ -21,9 +21,9 @@ import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -31,17 +31,18 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.RollingFileAppender;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.layout.HtmlLayout;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.apache.logging.log4j.core.util.IOUtils;
 import org.apache.logging.log4j.message.SimpleMessage;
 import org.hamcrest.Matchers;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Tests for LOG4J2-2760
@@ -50,10 +51,19 @@ public class RollingAppenderDirectWriteWithHtmlLayoutTest {
 
     private static final String DIR = "target/rolling-direct-htmlLayout";
 
-    public static LoggerContextRule loggerContextRule = new LoggerContextRule();
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            null,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    private Configuration config;
+
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) throws Exception {
+        this.config = loggerContext.getConfiguration();
+    }
 
     @Test
     public void testRollingFileAppenderWithHtmlLayout() throws Exception {
@@ -67,7 +77,6 @@ public class RollingAppenderDirectWriteWithHtmlLayoutTest {
 
     private void checkAppenderWithHtmlLayout(final boolean append) throws InterruptedException, IOException {
         final String prefix = "testHtml_" + (append ? "append_" : "noAppend_");
-        final Configuration config = loggerContextRule.getConfiguration();
         final RollingFileAppender appender = RollingFileAppender.newBuilder()
                 .setName("RollingHtml")
                 .setFilePattern(DIR + "/" + prefix + "_-%d{MM-dd-yy-HH-mm}-%i.html")
@@ -91,7 +100,7 @@ public class RollingAppenderDirectWriteWithHtmlLayoutTest {
             stopped = true;
             Thread.sleep(50);
             final File dir = new File(DIR);
-            assertTrue("Directory not created", dir.exists());
+            assertTrue(dir.exists(), "Directory not created");
             final File[] files = dir.listFiles();
             assertNotNull(files);
             assertThat(files, hasItemInArray(that(hasName(that(endsWith(".html"))))));
@@ -113,7 +122,7 @@ public class RollingAppenderDirectWriteWithHtmlLayoutTest {
                     }
                 }
             }
-            assertEquals("Incorrect number of events read.", count, foundEvents);
+            assertEquals(count, foundEvents, "Incorrect number of events read.");
         } finally {
             if (!stopped) {
                 appender.stop();
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithReconfigureTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithReconfigureTest.java
index f27ca883d3..006bd17d50 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithReconfigureTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithReconfigureTest.java
@@ -19,19 +19,18 @@ package org.apache.logging.log4j.core.appender.rolling;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.net.URI;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -44,25 +43,25 @@ public class RollingAppenderDirectWriteWithReconfigureTest {
 
     private static final int MAX_TRIES = 10;
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private Logger logger;
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingAppenderDirectWriteWithReconfigureTest.class.getName());
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingAppenderDirectWriteWithReconfigureTest.class.getName());
     }
 
     @Test
-    public void testRollingFileAppenderWithReconfigure() throws Exception {
+    public void testRollingFileAppenderWithReconfigure(final LoggerContext context) throws Exception {
         logger.debug("Before reconfigure");
 
         @SuppressWarnings("resource") // managed by the rule.
-        final LoggerContext context = loggerContextRule.getLoggerContext();
         final Configuration config = context.getConfiguration();
         context.setConfigLocation(new URI(CONFIG));
         context.reconfigure();
@@ -75,7 +74,7 @@ public class RollingAppenderDirectWriteWithReconfigureTest {
             }
         }
 
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
         final File[] files = dir.listFiles();
         assertNotNull(files);
         assertThat(dir.listFiles().length, is(equalTo(2)));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderNoUnconditionalDeleteTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderNoUnconditionalDeleteTest.java
index 803a898c20..77a527257f 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderNoUnconditionalDeleteTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderNoUnconditionalDeleteTest.java
@@ -16,60 +16,33 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 /**
  *
  */
-@RunWith(Parameterized.class)
 public class RollingAppenderNoUnconditionalDeleteTest {
 
-    private final File directory;
+    private File directory;
     private Logger logger;
 
-    @Parameterized.Parameters(name = "{0} \u2192 {1}")
-    public static Collection<Object[]> data() {
-        return Arrays.asList(new Object[][] { //
-            // @formatter:off
-            {"log4j-rolling-with-custom-delete-unconditional1.xml", "target/rolling-unconditional-delete1/test"}, //
-            {"log4j-rolling-with-custom-delete-unconditional2.xml", "target/rolling-unconditional-delete2/test"}, //
-            {"log4j-rolling-with-custom-delete-unconditional3.xml", "target/rolling-unconditional-delete3/test"}, //
-            // @formatter:on
-        });
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingAppenderNoUnconditionalDeleteTest.class.getName());
     }
 
-    @Rule
-    public LoggerContextRule loggerContextRule;
-
-    public RollingAppenderNoUnconditionalDeleteTest(final String configFile, final String dir) {
-        this.directory = new File(dir);
-        this.loggerContextRule = LoggerContextRule.createShutdownTimeoutLoggerContextRule(configFile);
-        deleteDir();
-        deleteDirParent();
-    }
-
-    @Before
-    public void setUp() {
-        this.logger = this.loggerContextRule.getLogger();
-    }
-
-    @Test
-    public void testAppender() throws Exception {
+    void testAppender() throws Exception {
         final int LINECOUNT = 18; // config has max="100"
         for (int i = 0; i < LINECOUNT; ++i) {
             // 30 chars per message: each message triggers a rollover
@@ -77,15 +50,46 @@ public class RollingAppenderNoUnconditionalDeleteTest {
         }
         Thread.sleep(100); // Allow time for rollover to complete
 
-        assertTrue("Dir " + directory + " should exist", directory.exists());
-        assertTrue("Dir " + directory + " should contain files", directory.listFiles().length > 0);
+        assertTrue(directory.exists(), "Dir " + directory + " should exist");
+        assertTrue(directory.listFiles().length > 0, "Dir " + directory + " should contain files");
 
         int total = 0;
         for (final File file : directory.listFiles()) {
             final List<String> lines = Files.readAllLines(file.toPath(), Charset.defaultCharset());
             total += lines.size();
         }
-        assertEquals("rolled over lines", LINECOUNT - 1, total);
+        assertEquals(LINECOUNT - 1, total, "rolled over lines");
+
+        cleanUp();
+    }
+
+    void cleanUp() {
+        deleteDir();
+        deleteDirParent();
+    }
+
+    @Test
+    @LoggerContextSource(value = "log4j-rolling-with-custom-delete-unconditional1.xml", timeout = 10)
+    public void RollingWithCustomUnconditionalDeleteTest1() throws Exception {
+        final String dir = "target/rolling-unconditional-delete1/test";
+        this.directory = new File(dir);
+        testAppender();
+    }
+
+    @Test
+    @LoggerContextSource(value = "log4j-rolling-with-custom-delete-unconditional2.xml", timeout = 10)
+    public void RollingWithCustomUnconditionalDeleteTest2() throws Exception {
+        final String dir = "target/rolling-unconditional-delete2/test";
+        this.directory = new File(dir);
+        testAppender();
+    }
+
+    @Test
+    @LoggerContextSource(value = "log4j-rolling-with-custom-delete-unconditional3.xml", timeout = 10)
+    public void RollingWithCustomUnconditionalDeleteTest3() throws Exception {
+        final String dir = "target/rolling-unconditional-delete3/test";
+        this.directory = new File(dir);
+        testAppender();
     }
 
     private void deleteDir() {
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderRestartTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderRestartTest.java
index 87945f909b..904d522865 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderRestartTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderRestartTest.java
@@ -16,14 +16,14 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static junit.framework.Assert.fail;
 import static org.apache.logging.log4j.core.test.hamcrest.Descriptors.that;
 import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 import java.io.File;
 import java.io.IOException;
@@ -39,14 +39,14 @@ import java.util.Arrays;
 import java.util.concurrent.TimeUnit;
 import org.apache.commons.io.file.PathUtils;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.RollingFileAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.hamcrest.Matcher;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class RollingAppenderRestartTest {
 
@@ -56,14 +56,17 @@ public class RollingAppenderRestartTest {
     private static final Path DIR = Paths.get("target/rolling-restart");
     private static final Path FILE = DIR.resolve("test.log");
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR.toAbsolutePath().toString(),
+            CONFIG,
+            RollingAppenderRestartTest.class.getName(),
+            this.getClass().getClassLoader(),
+            false,
+            true,
+            5);
 
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(
-            false, true, 5, DIR.toAbsolutePath().toString());
-
-    @BeforeClass
+    @BeforeAll
     public static void setup() throws Exception {
         tearDown();
         Files.createDirectories(DIR);
@@ -84,7 +87,7 @@ public class RollingAppenderRestartTest {
         assumeTrue(creationTime.equals(newTime) || creationTime.toMillis() == 0L);
     }
 
-    @AfterClass
+    @AfterAll
     public static void tearDown() throws IOException {
         if (Files.exists(DIR)) {
             PathUtils.deleteDirectory(DIR);
@@ -92,15 +95,15 @@ public class RollingAppenderRestartTest {
     }
 
     @Test
-    public void testAppender() throws Exception {
-        final Logger logger = loggerContextRule.getLogger();
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
+        final Logger logger = loggerContext.getLogger(RollingAppenderRestartTest.class.getName());
         logger.info("This is test message number 1");
         // The GZ compression takes place asynchronously.
         // Make sure it's done before validating.
         Thread.yield();
         final String name = "RollingFile";
-        final RollingFileAppender appender = loggerContextRule.getAppender(name);
-        assertNotNull(name, appender);
+        final RollingFileAppender appender = loggerContext.getConfiguration().getAppender(name);
+        assertNotNull(appender, name);
         if (appender.getManager().getSemaphore().tryAcquire(5, TimeUnit.SECONDS)) {
             // If we are in here, either the rollover is done or has not taken place yet.
             validate();
@@ -114,7 +117,7 @@ public class RollingAppenderRestartTest {
         final File[] files = DIR.toFile().listFiles();
         Arrays.sort(files);
         assertTrue(
-                "was expecting files with '.gz' suffix, found: " + Arrays.toString(files),
-                hasGzippedFile.matches(files));
+                hasGzippedFile.matches(files),
+                "was expecting files with '.gz' suffix, found: " + Arrays.toString(files));
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeCompressPermissionsTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeCompressPermissionsTest.java
index 98bc0989b7..56c35bdc85 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeCompressPermissionsTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeCompressPermissionsTest.java
@@ -16,23 +16,23 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.nio.file.Files;
 import java.nio.file.attribute.PosixFilePermissions;
 import java.util.concurrent.TimeUnit;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.apache.logging.log4j.core.util.FileUtils;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * LOG4J2-1699.
@@ -43,26 +43,27 @@ public class RollingAppenderSizeCompressPermissionsTest {
 
     private static final String DIR = "target/rollingpermissions1";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderSizeCompressPermissionsTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private Logger logger;
 
-    @BeforeClass
-    public static void beforeClass() {
-        Assume.assumeTrue(FileUtils.isFilePosixAttributeViewSupported());
+    @BeforeAll
+    public static void beforeAll() {
+        Assumptions.assumeTrue(FileUtils.isFilePosixAttributeViewSupported());
     }
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingAppenderSizeCompressPermissionsTest.class.getName());
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingAppenderSizeCompressPermissionsTest.class.getName());
     }
 
     @Test
-    public void testAppenderCompressPermissions() throws Exception {
+    public void testAppenderCompressPermissions(final LoggerContext loggerContext) throws Exception {
         for (int i = 0; i < 500; ++i) {
             final String message = "This is test message number " + i;
             logger.debug(message);
@@ -70,11 +71,11 @@ public class RollingAppenderSizeCompressPermissionsTest {
                 Thread.sleep(500);
             }
         }
-        if (!loggerContextRule.getLoggerContext().stop(30, TimeUnit.SECONDS)) {
-            System.err.println("Could not stop cleanly " + loggerContextRule + " for " + this);
+        if (!loggerContext.stop(30, TimeUnit.SECONDS)) {
+            System.err.println("Could not stop cleanly " + loggerContext + " for " + this);
         }
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists());
+        assertTrue(dir.exists(), "Directory not created");
         final File[] files = dir.listFiles();
         assertNotNull(files);
         int gzippedFiles1 = 0;
@@ -97,8 +98,8 @@ public class RollingAppenderSizeCompressPermissionsTest {
                 assertEquals("rwx------", PosixFilePermissions.toString(Files.getPosixFilePermissions(file.toPath())));
             }
         }
-        assertTrue("Files not rolled : " + files.length, files.length > 2);
-        assertTrue("Files 1 gzipped not rolled : " + gzippedFiles1, gzippedFiles1 > 0);
-        assertTrue("Files 2 gzipped not rolled : " + gzippedFiles2, gzippedFiles2 > 0);
+        assertTrue(files.length > 2, "Files not rolled : " + files.length);
+        assertTrue(gzippedFiles1 > 0, "Files 1 gzipped not rolled : " + gzippedFiles1);
+        assertTrue(gzippedFiles2 > 0, "Files 2 gzipped not rolled : " + gzippedFiles2);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest.java
index 4b49a59f12..7fec8c459b 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest.java
@@ -16,62 +16,41 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 import java.util.stream.IntStream;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.RollingFileAppender;
 import org.apache.logging.log4j.core.pattern.ArrayPatternConverter;
 import org.apache.logging.log4j.core.pattern.FormattingInfo;
 import org.apache.logging.log4j.core.pattern.IntegerPatternConverter;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.apache.logging.log4j.core.test.junit.CleanFolders;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
  */
-@RunWith(Parameterized.class)
-public class RollingAppenderSizeMaxWidthTest implements RolloverListener {
-    @Parameterized.Parameters(name = "{0}")
-    public static Collection<Object[]> data() {
-        return Arrays.asList(new Object[][] {
-            {
-                new LoggerContextRule("log4j-rolling-size-max-width-1.xml"),
-            },
-            {
-                new LoggerContextRule("log4j-rolling-size-max-width-2.xml"),
-            },
-            {
-                new LoggerContextRule("log4j-rolling-size-max-width-3.xml"),
-            },
-            {
-                new LoggerContextRule("log4j-rolling-size-max-width-4.xml"),
-            },
-        });
-    }
+public abstract class RollingAppenderSizeMaxWidthTest implements RolloverListener {
 
     private static final String DIR = "target/rolling-max-width/archive";
     private static final String MESSAGE = "This is test message number ";
-    private static final int COUNT = 10000;
     private static final int[] POWERS_OF_10 = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
     };
-    public LoggerContextRule loggerContextRule;
 
-    @Rule
-    public RuleChain chain;
+    private LoggerContext context;
+
+    @RegisterExtension
+    private CleanFolders cleanFolders;
 
     List<String> rolledFileNames = new ArrayList<>();
     int min;
@@ -90,15 +69,16 @@ public class RollingAppenderSizeMaxWidthTest implements RolloverListener {
         return POWERS_OF_10[pow];
     }
 
-    public RollingAppenderSizeMaxWidthTest(final LoggerContextRule loggerContextRule) {
-        this.loggerContextRule = loggerContextRule;
-        this.chain = loggerContextRule.withCleanFoldersRule(DIR);
+    public RollingAppenderSizeMaxWidthTest(final LoggerContext context) {
+        this.context = context;
+        this.cleanFolders = new CleanFolders(DIR);
     }
 
-    @Before
+    @BeforeEach
     public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingAppenderSizeMaxWidthTest.class.getName());
-        final RollingFileAppender app = (RollingFileAppender) loggerContextRule.getRequiredAppender("RollingFile");
+        this.logger = context.getLogger(RollingAppenderSizeMaxWidthTest.class.getName());
+        final RollingFileAppender app =
+                (RollingFileAppender) context.getConfiguration().getAppender("RollingFile");
         app.getManager().addRolloverListener(this);
         final ArrayPatternConverter[] patternConverters =
                 app.getManager().getPatternProcessor().getPatternConverters();
@@ -128,17 +108,17 @@ public class RollingAppenderSizeMaxWidthTest implements RolloverListener {
         } else {
             policy = app.getTriggeringPolicy();
         }
-        assertNotNull("No SizeBasedTriggeringPolicy", policy);
+        assertNotNull(policy, "No SizeBasedTriggeringPolicy");
         rolloverSize = policy.getMaxFileSize();
     }
 
     @Test
     public void testAppender() {
         if (minWidth > 0) {
-            assertTrue("min must be greater than or equal to the minimum width", min > -powerOfTen(minWidth));
+            assertTrue(min > -powerOfTen(minWidth), "min must be greater than or equal to the minimum width");
         }
         if (maxWidth < Integer.MAX_VALUE) {
-            assertTrue("max must be less than or equal to the maximum width", max <= powerOfTen(maxWidth));
+            assertTrue(max <= powerOfTen(maxWidth), "max must be less than or equal to the maximum width");
         }
         long bytes = 0;
         for (int i = 0; i < 10000; ++i) {
@@ -149,21 +129,21 @@ public class RollingAppenderSizeMaxWidthTest implements RolloverListener {
         final long minExpected = ((bytes / rolloverSize) * 95) / 100;
         final long maxExpected = ((bytes / rolloverSize) * 105) / 100;
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists());
+        assertTrue(dir.exists(), "Directory not created");
         final File[] files = dir.listFiles();
         assertNotNull(files);
         assertTrue(
-                "Not enough rollovers: expected: " + minExpected + ", actual: " + rolloverCount,
-                rolloverCount + 1 >= minExpected);
+                rolloverCount + 1 >= minExpected,
+                "Not enough rollovers: expected: " + minExpected + ", actual: " + rolloverCount);
         assertTrue(
-                "Too many rollovers: expected: " + maxExpected + ", actual: " + rolloverCount,
-                rolloverCount <= maxExpected);
+                rolloverCount <= maxExpected,
+                "Too many rollovers: expected: " + maxExpected + ", actual: " + rolloverCount);
         final int maxFiles = max - min + 1;
         final int maxExpectedFiles = Math.min(maxFiles, rolloverCount);
         assertEquals(
-                "More files than expected. expected: " + maxExpectedFiles + ", actual: " + files.length,
                 maxExpectedFiles,
-                files.length);
+                files.length,
+                "More files than expected. expected: " + maxExpectedFiles + ", actual: " + files.length);
     }
 
     @Override
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest1.java
similarity index 66%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest1.java
index 6644ece96a..1745f6481b 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest1.java
@@ -16,20 +16,13 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 
-/**
- * Tests https://issues.apache.org/jira/browse/LOG4J2-1967
- */
-public class RollingFileAppenderReconfigureTest {
-
-    @Rule
-    public final LoggerContextRule loggerContextRule = new LoggerContextRule("rolling-file-appender-reconfigure.xml");
+@LoggerContextSource("log4j-rolling-size-max-width-1.xml")
+public class RollingAppenderSizeMaxWidthTest1 extends RollingAppenderSizeMaxWidthTest {
 
-    @Test
-    public void testReconfigure() {
-        loggerContextRule.reconfigure();
+    public RollingAppenderSizeMaxWidthTest1(LoggerContext context) {
+        super(context);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest2.java
similarity index 66%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest2.java
index 6644ece96a..b99fabd765 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest2.java
@@ -16,20 +16,13 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 
-/**
- * Tests https://issues.apache.org/jira/browse/LOG4J2-1967
- */
-public class RollingFileAppenderReconfigureTest {
-
-    @Rule
-    public final LoggerContextRule loggerContextRule = new LoggerContextRule("rolling-file-appender-reconfigure.xml");
+@LoggerContextSource("log4j-rolling-size-max-width-2.xml")
+public class RollingAppenderSizeMaxWidthTest2 extends RollingAppenderSizeMaxWidthTest {
 
-    @Test
-    public void testReconfigure() {
-        loggerContextRule.reconfigure();
+    public RollingAppenderSizeMaxWidthTest2(LoggerContext context) {
+        super(context);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest3.java
similarity index 66%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest3.java
index 6644ece96a..0b62d2245d 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest3.java
@@ -16,20 +16,13 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 
-/**
- * Tests https://issues.apache.org/jira/browse/LOG4J2-1967
- */
-public class RollingFileAppenderReconfigureTest {
-
-    @Rule
-    public final LoggerContextRule loggerContextRule = new LoggerContextRule("rolling-file-appender-reconfigure.xml");
+@LoggerContextSource("log4j-rolling-size-max-width-3.xml")
+public class RollingAppenderSizeMaxWidthTest3 extends RollingAppenderSizeMaxWidthTest {
 
-    @Test
-    public void testReconfigure() {
-        loggerContextRule.reconfigure();
+    public RollingAppenderSizeMaxWidthTest3(LoggerContext context) {
+        super(context);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest4.java
similarity index 66%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest4.java
index 6644ece96a..97d0f4cde1 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeMaxWidthTest4.java
@@ -16,20 +16,13 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 
-/**
- * Tests https://issues.apache.org/jira/browse/LOG4J2-1967
- */
-public class RollingFileAppenderReconfigureTest {
-
-    @Rule
-    public final LoggerContextRule loggerContextRule = new LoggerContextRule("rolling-file-appender-reconfigure.xml");
+@LoggerContextSource("log4j-rolling-size-max-width-4.xml")
+public class RollingAppenderSizeMaxWidthTest4 extends RollingAppenderSizeMaxWidthTest {
 
-    @Test
-    public void testReconfigure() {
-        loggerContextRule.reconfigure();
+    public RollingAppenderSizeMaxWidthTest4(LoggerContext context) {
+        super(context);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeWithTimeTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeWithTimeTest.java
index abe97560e8..eaa8351bf6 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeWithTimeTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeWithTimeTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -29,11 +29,11 @@ import java.util.List;
 import java.util.concurrent.TimeUnit;
 import org.apache.commons.compress.utils.IOUtils;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * LOG4J2-2602.
@@ -44,21 +44,22 @@ public class RollingAppenderSizeWithTimeTest {
 
     private static final String DIR = "target/rolling-size-test";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderSizeWithTimeTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private Logger logger;
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingAppenderSizeWithTimeTest.class.getName());
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingAppenderSizeWithTimeTest.class.getName());
     }
 
     @Test
-    public void testAppender() throws Exception {
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
         final List<String> messages = new ArrayList<>();
         for (int i = 0; i < 5000; ++i) {
             final String message = "This is test message number " + i;
@@ -68,11 +69,11 @@ public class RollingAppenderSizeWithTimeTest {
                 Thread.sleep(10);
             }
         }
-        if (!loggerContextRule.getLoggerContext().stop(30, TimeUnit.SECONDS)) {
-            System.err.println("Could not stop cleanly " + loggerContextRule + " for " + this);
+        if (!loggerContext.stop(30, TimeUnit.SECONDS)) {
+            System.err.println("Could not stop cleanly " + loggerContext + " for " + this);
         }
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists());
+        assertTrue(dir.exists(), "Directory not created");
         final File[] files = dir.listFiles();
         assertNotNull(files);
         for (final File file : files) {
@@ -91,7 +92,7 @@ public class RollingAppenderSizeWithTimeTest {
                 messages.remove(line);
             }
         }
-        assertTrue("Log messages lost : " + messages.size(), messages.isEmpty());
-        assertTrue("Files not rolled : " + files.length, files.length > 2);
+        assertTrue(messages.isEmpty(), "Log messages lost : " + messages.size());
+        assertTrue(files.length > 2, "Files not rolled : " + files.length);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeAndSizeDirectTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeAndSizeDirectTest.java
index 31c04d3909..71442f0c32 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeAndSizeDirectTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeAndSizeDirectTest.java
@@ -21,16 +21,16 @@ import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -41,17 +41,18 @@ public class RollingAppenderTimeAndSizeDirectTest {
 
     private static final String DIR = "target/rolling3Direct";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderTimeAndSizeDirectTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private Logger logger;
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingAppenderTimeAndSizeDirectTest.class.getName());
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingAppenderTimeAndSizeDirectTest.class.getName());
     }
 
     @Test
@@ -62,7 +63,7 @@ public class RollingAppenderTimeAndSizeDirectTest {
         }
         Thread.sleep(50);
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
         final File[] files = dir.listFiles();
         assertNotNull(files);
         assertThat(files, hasItemInArray(that(hasName(that(endsWith(".gz"))))));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeAndSizeTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeAndSizeTest.java
index a04471dcac..8f0ecdc58d 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeAndSizeTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeAndSizeTest.java
@@ -21,10 +21,10 @@ import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.nio.file.Files;
@@ -32,11 +32,11 @@ import java.nio.file.attribute.FileTime;
 import java.util.Arrays;
 import java.util.Random;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -47,24 +47,25 @@ public class RollingAppenderTimeAndSizeTest {
 
     private static final String DIR = "target/rolling3/test";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderTimeAndSizeTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private Logger logger;
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingAppenderTimeAndSizeTest.class.getName());
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingAppenderTimeAndSizeTest.class.getName());
     }
 
     @Test
     public void testAppender() throws Exception {
         final Random rand = new Random();
         final File logFile = new File("target/rolling3/rollingtest.log");
-        assertTrue("target/rolling3/rollingtest.log does not exist", logFile.exists());
+        assertTrue(logFile.exists(), "target/rolling3/rollingtest.log does not exist");
         final FileTime time = (FileTime) Files.getAttribute(logFile.toPath(), "creationTime");
         for (int j = 0; j < 100; ++j) {
             final int count = rand.nextInt(50);
@@ -75,7 +76,7 @@ public class RollingAppenderTimeAndSizeTest {
         }
         Thread.sleep(50);
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
         final File[] files = dir.listFiles();
         Arrays.sort(files);
         assertNotNull(files);
@@ -94,11 +95,11 @@ public class RollingAppenderTimeAndSizeTest {
             fileCounter = previous.equals(fileParts[1]) ? ++fileCounter : 1;
             previous = fileParts[1];
             assertEquals(
-                    "Incorrect file name. Expected counter value of " + fileCounter + " in " + actual,
                     Integer.toString(fileCounter),
-                    fileParts[2]);
+                    fileParts[2],
+                    "Incorrect file name. Expected counter value of " + fileCounter + " in " + actual);
         }
         final FileTime endTime = (FileTime) Files.getAttribute(logFile.toPath(), "creationTime");
-        assertNotEquals("Creation times are equal", time, endTime);
+        assertNotEquals(time, endTime, "Creation times are equal");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeTest.java
index e5e68f593e..48edfe1e73 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTimeTest.java
@@ -20,16 +20,16 @@ import static org.apache.logging.log4j.core.test.hamcrest.Descriptors.that;
 import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
 import org.hamcrest.Matcher;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -39,15 +39,16 @@ public class RollingAppenderTimeTest {
     private static final String CONFIG = "log4j-rolling2.xml";
     private static final String DIR = "target/rolling2";
 
-    private final LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingAppenderDeleteScriptTest.class.getName(),
+            this.getClass().getClassLoader());
 
     @Test
-    public void testAppender() throws Exception {
-        final Logger logger = loggerContextRule.getLogger();
+    public void testAppender(final LoggerContext loggerContext) throws Exception {
+        final Logger logger = loggerContext.getLogger(RollingAppenderTimeTest.class.getName());
         logger.debug("This is test message number 1");
         Thread.sleep(1500);
         // Trigger the rollover
@@ -55,7 +56,7 @@ public class RollingAppenderTimeTest {
             logger.debug("This is test message number " + i + 1);
         }
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
 
         final int MAX_TRIES = 20;
         final Matcher<File[]> hasGzippedFile = hasItemInArray(that(hasName(that(endsWith(".gz")))));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderUncompressedTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderUncompressedTest.java
index 66568da524..cbccc12ecd 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderUncompressedTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderUncompressedTest.java
@@ -16,20 +16,18 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
-import org.apache.logging.log4j.core.test.junit.CleanFolders;
 import org.apache.logging.log4j.status.StatusLogger;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
 
 /**
  *
@@ -41,16 +39,20 @@ public class RollingAppenderUncompressedTest {
 
     private final Logger logger = LogManager.getLogger(RollingAppenderUncompressedTest.class.getName());
 
-    @ClassRule
-    public static CleanFolders rule = new CleanFolders(CONFIG);
+    // @RegisterExtension
+    // private CleanFoldersRuleExtension cleanFolders = new CleanFoldersRuleExtension(
+    //         DIR,
+    //         CONFIG,
+    //         RollingAppenderUncompressedTest.class.getName(),
+    //         this.getClass().getClassLoader());
 
-    @BeforeClass
-    public static void setupClass() {
+    @BeforeAll
+    public static void setupAll() {
         System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
     }
 
-    @AfterClass
-    public static void cleanupClass() {
+    @AfterAll
+    public static void cleanupAll() {
         System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
         final LoggerContext ctx = LoggerContext.getContext();
         ctx.reconfigure();
@@ -63,7 +65,7 @@ public class RollingAppenderUncompressedTest {
             logger.debug("This is test message number " + i);
         }
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
         final File[] files = dir.listFiles();
         assertNotNull(files);
         boolean found = false;
@@ -74,6 +76,6 @@ public class RollingAppenderUncompressedTest {
                 break;
             }
         }
-        assertTrue("No archived files found", found);
+        assertTrue(found, "No archived files found");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectSizeTimeNewDirectoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectSizeTimeNewDirectoryTest.java
index f871587f9b..e4feb33d16 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectSizeTimeNewDirectoryTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectSizeTimeNewDirectoryTest.java
@@ -16,7 +16,7 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.Collections;
@@ -25,11 +25,11 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.RollingFileAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * This test attempts to validate that logging rolls when the file size exceeds 5KB or every second.
@@ -43,20 +43,21 @@ public class RollingDirectSizeTimeNewDirectoryTest implements RolloverListener {
     // Note that the path is hardcoded in the configuration!
     private static final String DIR = "target/rolling-size-time-new-directory";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingDirectSizeTimeNewDirectoryTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private final Map<String, AtomicInteger> rolloverFiles = new HashMap<>();
 
     @Test
-    public void streamClosedError() throws Exception {
-        ((RollingFileAppender) loggerContextRule.getAppender("RollingFile"))
+    public void streamClosedError(final LoggerContext loggerContext) throws Exception {
+        ((RollingFileAppender) loggerContext.getConfiguration().getAppender("RollingFile"))
                 .getManager()
                 .addRolloverListener(this);
-        final Logger logger = loggerContextRule.getLogger(RollingDirectSizeTimeNewDirectoryTest.class);
+        final Logger logger = loggerContext.getLogger(RollingDirectSizeTimeNewDirectoryTest.class);
 
         for (int i = 0; i < 1000; i++) {
             logger.info("nHq6p9kgfvWfjzDRYbZp");
@@ -66,10 +67,10 @@ public class RollingDirectSizeTimeNewDirectoryTest implements RolloverListener {
             logger.info("nHq6p9kgfvWfjzDRYbZp");
         }
 
-        assertTrue("A time based rollover did not occur", rolloverFiles.size() > 1);
+        assertTrue(rolloverFiles.size() > 1, "A time based rollover did not occur");
         final int maxFiles = Collections.max(rolloverFiles.values(), Comparator.comparing(AtomicInteger::get))
                 .get();
-        assertTrue("No size based rollovers occurred", maxFiles > 1);
+        assertTrue(maxFiles > 1, "No size based rollovers occurred");
     }
 
     @Override
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectTimeNewDirectoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectTimeNewDirectoryTest.java
index 1d7f83bff3..dc6deeaf8d 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectTimeNewDirectoryTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingDirectTimeNewDirectoryTest.java
@@ -16,8 +16,8 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.Arrays;
@@ -25,10 +25,10 @@ import java.util.Iterator;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.filefilter.TrueFileFilter;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class RollingDirectTimeNewDirectoryTest {
 
@@ -37,11 +37,12 @@ public class RollingDirectTimeNewDirectoryTest {
     // Note that the path is hardcoded in the configuration!
     private static final String DIR = "target/rolling-folder-direct";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingDirectTimeNewDirectoryTest.class.getName(),
+            this.getClass().getClassLoader());
 
     /**
      * This test logs directly to the target file. Rollover is set to happen once per second. We pause once
@@ -50,9 +51,9 @@ public class RollingDirectTimeNewDirectoryTest {
      * @throws Exception
      */
     @Test
-    public void streamClosedError() throws Exception {
+    public void streamClosedError(final LoggerContext loggerContext) throws Exception {
 
-        final Logger logger = loggerContextRule.getLogger(RollingDirectTimeNewDirectoryTest.class.getName());
+        final Logger logger = loggerContext.getLogger(RollingDirectTimeNewDirectoryTest.class.getName());
 
         for (int i = 0; i < 1000; i++) {
             logger.info("nHq6p9kgfvWfjzDRYbZp");
@@ -71,17 +72,18 @@ public class RollingDirectTimeNewDirectoryTest {
 
             final int minExpectedLogFolderCount = 2;
             assertTrue(
-                    "was expecting at least " + minExpectedLogFolderCount + " folders, " + "found " + logFolders.length,
-                    logFolders.length >= minExpectedLogFolderCount);
+                    logFolders.length >= minExpectedLogFolderCount,
+                    "was expecting at least " + minExpectedLogFolderCount + " folders, " + "found "
+                            + logFolders.length);
 
             for (File logFolder : logFolders) {
                 final File[] logFiles = logFolder.listFiles();
                 if (logFiles != null) {
-                    assertTrue("Only 1 file per folder expected: got " + logFiles.length, logFiles.length <= 1);
+                    assertTrue(logFiles.length <= 1, "Only 1 file per folder expected: got " + logFiles.length);
                     totalFiles += logFiles.length;
                 }
             }
-            assertTrue("Expected at least 2 files", totalFiles >= 2);
+            assertTrue(totalFiles >= 2, "Expected at least 2 files");
 
         } catch (AssertionError error) {
             System.out.format("log directory (%s) contents:%n", DIR);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderInterruptedThreadTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderInterruptedThreadTest.java
index bab55e5bce..e343793b72 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderInterruptedThreadTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderInterruptedThreadTest.java
@@ -19,7 +19,7 @@ package org.apache.logging.log4j.core.appender.rolling;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.hasItem;
 import static org.hamcrest.Matchers.instanceOf;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import org.apache.logging.log4j.Level;
@@ -31,10 +31,10 @@ import org.apache.logging.log4j.core.config.Configurator;
 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
 import org.apache.logging.log4j.core.test.junit.CleanFolders;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Tests <a href="https://issues.apache.org/jira/browse/LOG4J2-1798"/>.
@@ -44,12 +44,12 @@ public class RollingFileAppenderInterruptedThreadTest {
     private static final String ROLLING_APPENDER_FILES_DIR =
             "target/" + RollingFileAppenderInterruptedThreadTest.class.getSimpleName();
 
-    @Rule
-    public CleanFolders cleanFolders = new CleanFolders(true, false, 3, ROLLING_APPENDER_FILES_DIR);
-
     LoggerContext loggerContext;
 
-    @Before
+    @RegisterExtension
+    private CleanFolders cleanFolders = new CleanFolders(true, false, 3, ROLLING_APPENDER_FILES_DIR);
+
+    @BeforeEach
     public void setUp() {
         final ConfigurationBuilder<?> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
         builder.setConfigurationName("LOG4J2-1798 test");
@@ -70,7 +70,7 @@ public class RollingFileAppenderInterruptedThreadTest {
         loggerContext = Configurator.initialize(builder.build());
     }
 
-    @After
+    @AfterEach
     public void tearDown() {
         Configurator.shutdown(loggerContext);
         loggerContext = null;
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
index 6644ece96a..41522f6777 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureTest.java
@@ -16,20 +16,18 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.Test;
 
 /**
  * Tests https://issues.apache.org/jira/browse/LOG4J2-1967
  */
 public class RollingFileAppenderReconfigureTest {
 
-    @Rule
-    public final LoggerContextRule loggerContextRule = new LoggerContextRule("rolling-file-appender-reconfigure.xml");
-
     @Test
-    public void testReconfigure() {
-        loggerContextRule.reconfigure();
+    @LoggerContextSource(value = "rolling-file-appender-reconfigure.xml")
+    public void testReconfigure(final LoggerContext loggerContext) {
+        loggerContext.reconfigure();
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureUndefinedSystemPropertyTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureUndefinedSystemPropertyTest.java
index 84a20894d2..86a788a45b 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureUndefinedSystemPropertyTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingFileAppenderReconfigureUndefinedSystemPropertyTest.java
@@ -16,21 +16,18 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.Test;
 
 /**
  * Tests https://issues.apache.org/jira/browse/LOG4J2-1967
  */
 public class RollingFileAppenderReconfigureUndefinedSystemPropertyTest {
 
-    @Rule
-    public final LoggerContextRule loggerContextRule =
-            new LoggerContextRule("src/test/rolling-file-appender-reconfigure.original.xml");
-
     @Test
-    public void testReconfigure() {
-        loggerContextRule.reconfigure();
+    @LoggerContextSource("src/test/rolling-file-appender-reconfigure.original.xml")
+    public void testReconfigure(final LoggerContext loggerContext) {
+        loggerContext.reconfigure();
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingNewDirectoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingNewDirectoryTest.java
index e720a33ea0..50abfd8f86 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingNewDirectoryTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingNewDirectoryTest.java
@@ -16,16 +16,16 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Tests
@@ -35,17 +35,18 @@ public class RollingNewDirectoryTest {
 
     private static final String DIR = "target/rolling-new-directory";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingNewDirectoryTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private Logger logger;
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingNewDirectoryTest.class.getName());
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingNewDirectoryTest.class.getName());
     }
 
     @Test
@@ -55,7 +56,7 @@ public class RollingNewDirectoryTest {
             Thread.sleep(300);
         }
         final File dir = new File(DIR);
-        assertNotNull("No directory created", dir);
-        assertTrue("Child irectories not created", dir.exists() && dir.listFiles().length > 2);
+        assertNotNull(dir, "No directory created");
+        assertTrue(dir.exists() && dir.listFiles().length > 2, "Child irectories not created");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteTest.java
index d74a0637bd..ba2590e7ca 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteTest.java
@@ -21,16 +21,16 @@ import static org.apache.logging.log4j.core.test.hamcrest.FileMatchers.hasName;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.endsWith;
 import static org.hamcrest.Matchers.hasItemInArray;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -41,17 +41,18 @@ public class RollingRandomAppenderDirectWriteTest {
 
     private static final String DIR = "target/rolling-random-direct";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingRandomAppenderDirectWriteTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private Logger logger;
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingRandomAppenderDirectWriteTest.class.getName());
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingRandomAppenderDirectWriteTest.class.getName());
     }
 
     @Test
@@ -61,7 +62,7 @@ public class RollingRandomAppenderDirectWriteTest {
         }
         Thread.sleep(50);
         final File dir = new File(DIR);
-        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        assertTrue(dir.exists() && dir.listFiles().length > 0, "Directory not created");
         final File[] files = dir.listFiles();
         assertNotNull(files);
         assertThat(files, hasItemInArray(that(hasName(that(endsWith(".gz"))))));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteWithFilenameTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteWithFilenameTest.java
index 8ae8e94eb3..03c43242b0 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteWithFilenameTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteWithFilenameTest.java
@@ -16,15 +16,15 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import static org.junit.Assert.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 
 import java.io.File;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFoldersRuleExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -35,22 +35,23 @@ public class RollingRandomAppenderDirectWriteWithFilenameTest {
 
     private static final String DIR = "target/random-1833";
 
-    public static LoggerContextRule loggerContextRule =
-            LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+    @RegisterExtension
+    CleanFoldersRuleExtension extension = new CleanFoldersRuleExtension(
+            DIR,
+            CONFIG,
+            RollingRandomAppenderDirectWriteWithFilenameTest.class.getName(),
+            this.getClass().getClassLoader());
 
     private Logger logger;
 
-    @Before
-    public void setUp() {
-        this.logger = loggerContextRule.getLogger(RollingRandomAppenderDirectWriteWithFilenameTest.class.getName());
+    @BeforeEach
+    public void setUp(final LoggerContext loggerContext) {
+        this.logger = loggerContext.getLogger(RollingRandomAppenderDirectWriteWithFilenameTest.class.getName());
     }
 
     @Test
     public void testAppender() {
         final File dir = new File(DIR);
-        assertFalse("Directory created", dir.exists());
+        assertFalse(dir.exists(), "Directory created");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderGroovyStaticVarsTest.java
similarity index 57%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderGroovyStaticVarsTest.java
index bd1990746e..fffba48473 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderGroovyStaticVarsTest.java
@@ -14,21 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.core.appender.db.jdbc;
+package org.apache.logging.log4j.core.appender.routing;
 
-import java.io.IOException;
-import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
 
-/**
- * Abstracts H2 test clean up.
- */
-public abstract class AbstractH2Test {
-
-    @AfterClass
-    @BeforeClass
-    public static void classDeleteDir() throws IOException {
-        JdbcH2TestHelper.deleteDir();
+@LoggerContextSource(
+        value = "log4j-routing-script-staticvars-groovy.xml",
+        reconfigure = ReconfigurationPolicy.BEFORE_EACH)
+public class DefaultRouteScriptAppenderGroovyStaticVarsTest extends DefaultRouteScriptAppenderTest {
+    public DefaultRouteScriptAppenderGroovyStaticVarsTest(LoggerContext context) {
+        super(context, true);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderGroovyTest.java
similarity index 58%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderGroovyTest.java
index bd1990746e..fd0aed2086 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderGroovyTest.java
@@ -14,21 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.core.appender.db.jdbc;
+package org.apache.logging.log4j.core.appender.routing;
 
-import java.io.IOException;
-import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
 
-/**
- * Abstracts H2 test clean up.
- */
-public abstract class AbstractH2Test {
-
-    @AfterClass
-    @BeforeClass
-    public static void classDeleteDir() throws IOException {
-        JdbcH2TestHelper.deleteDir();
+@LoggerContextSource(
+        value = "log4j-routing-default-route-script-groovy.xml",
+        reconfigure = ReconfigurationPolicy.BEFORE_EACH)
+public class DefaultRouteScriptAppenderGroovyTest extends DefaultRouteScriptAppenderTest {
+    public DefaultRouteScriptAppenderGroovyTest(LoggerContext context) {
+        super(context, false);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderJavaScriptStaticVarsTest.java
similarity index 56%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderJavaScriptStaticVarsTest.java
index bd1990746e..863fdbfadb 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderJavaScriptStaticVarsTest.java
@@ -14,21 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.core.appender.db.jdbc;
+package org.apache.logging.log4j.core.appender.routing;
 
-import java.io.IOException;
-import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
 
-/**
- * Abstracts H2 test clean up.
- */
-public abstract class AbstractH2Test {
-
-    @AfterClass
-    @BeforeClass
-    public static void classDeleteDir() throws IOException {
-        JdbcH2TestHelper.deleteDir();
+@LoggerContextSource(
+        value = "log4j-routing-script-staticvars-javascript.xml",
+        reconfigure = ReconfigurationPolicy.BEFORE_EACH)
+public class DefaultRouteScriptAppenderJavaScriptStaticVarsTest extends DefaultRouteScriptAppenderTest {
+    public DefaultRouteScriptAppenderJavaScriptStaticVarsTest(LoggerContext context) {
+        super(context, true);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderJavaScriptTest.java
similarity index 57%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderJavaScriptTest.java
index bd1990746e..a2c521b5a8 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderJavaScriptTest.java
@@ -14,21 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.core.appender.db.jdbc;
+package org.apache.logging.log4j.core.appender.routing;
 
-import java.io.IOException;
-import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
 
-/**
- * Abstracts H2 test clean up.
- */
-public abstract class AbstractH2Test {
-
-    @AfterClass
-    @BeforeClass
-    public static void classDeleteDir() throws IOException {
-        JdbcH2TestHelper.deleteDir();
+@LoggerContextSource(
+        value = "log4j-routing-default-route-script-javascript.xml",
+        reconfigure = ReconfigurationPolicy.BEFORE_EACH)
+public class DefaultRouteScriptAppenderJavaScriptTest extends DefaultRouteScriptAppenderTest {
+    public DefaultRouteScriptAppenderJavaScriptTest(LoggerContext context) {
+        super(context, false);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
index 61c37e4914..b5d6d83e07 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
@@ -16,55 +16,41 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentMap;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.MarkerManager;
+import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.AppenderControl;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
 import org.apache.logging.log4j.core.util.Constants;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
 
 /**
  *
  */
-@RunWith(Parameterized.class)
-public class DefaultRouteScriptAppenderTest {
-
-    @Parameterized.Parameters(name = "{0} {1}")
-    public static Object[][] getParameters() {
-        // @formatter:off
-        return new Object[][] {
-            {"log4j-routing-default-route-script-groovy.xml", false},
-            {"log4j-routing-default-route-script-javascript.xml", false},
-            {"log4j-routing-script-staticvars-javascript.xml", true},
-            {"log4j-routing-script-staticvars-groovy.xml", true},
-        };
-        // @formatter:on
-    }
+public abstract class DefaultRouteScriptAppenderTest {
 
-    @BeforeClass
+    @BeforeAll
     public static void beforeClass() {
         System.setProperty(Constants.SCRIPT_LANGUAGES, "Groovy, Javascript");
     }
 
-    @Rule
-    public final LoggerContextRule loggerContextRule;
+    public final LoggerContext loggerContext;
 
     private final boolean expectBindingEntries;
 
-    public DefaultRouteScriptAppenderTest(final String configLocation, final boolean expectBindingEntries) {
-        this.loggerContextRule = new LoggerContextRule(configLocation);
+    public DefaultRouteScriptAppenderTest(final LoggerContext context, boolean expectBindingEntries) {
+        this.loggerContext = context;
         this.expectBindingEntries = expectBindingEntries;
     }
 
@@ -72,68 +58,67 @@ public class DefaultRouteScriptAppenderTest {
         final RoutingAppender routingAppender = getRoutingAppender();
         final ConcurrentMap<Object, Object> map = routingAppender.getScriptStaticVariables();
         if (expectBindingEntries) {
-            assertEquals("TestValue2", map.get("TestKey"));
-            assertEquals("HEXDUMP", map.get("MarkerName"));
+            assertEquals(map.get("TestKey"), "TestValue2");
+            assertEquals(map.get("MarkerName"), "HEXDUMP");
         }
     }
 
     private ListAppender getListAppender() {
         final String key = "Service2";
         final RoutingAppender routingAppender = getRoutingAppender();
-        Assert.assertTrue(routingAppender.isStarted());
+        assertTrue(routingAppender.isStarted());
         final Map<String, AppenderControl> appenders = routingAppender.getAppenders();
         final AppenderControl appenderControl = appenders.get(key);
-        assertNotNull("No appender control generated for '" + key + "'; appenders = " + appenders, appenderControl);
+        assertNotNull(appenderControl, "No appender control generated for '" + key + "'; appenders = " + appenders);
         final ListAppender listAppender = (ListAppender) appenderControl.getAppender();
         return listAppender;
     }
 
     private RoutingAppender getRoutingAppender() {
-        return loggerContextRule.getRequiredAppender("Routing", RoutingAppender.class);
+        return (RoutingAppender) loggerContext.getConfiguration().getAppenders().get("Routing");
     }
 
     private void logAndCheck() {
         final Marker marker = MarkerManager.getMarker("HEXDUMP");
-        final Logger logger = loggerContextRule.getLogger(DefaultRouteScriptAppenderTest.class);
+        final Logger logger = (Logger) loggerContext.getLogger(DefaultRouteScriptAppenderTest.class);
         logger.error("Hello");
         final ListAppender listAppender = getListAppender();
-        assertEquals("Incorrect number of events", 1, listAppender.getEvents().size());
+        assertEquals(1, listAppender.getEvents().size(), "Incorrect number of events");
         logger.error("World");
-        assertEquals("Incorrect number of events", 2, listAppender.getEvents().size());
+        assertEquals(2, listAppender.getEvents().size(), "Incorrect number of events");
         logger.error(marker, "DEADBEEF");
-        assertEquals("Incorrect number of events", 3, listAppender.getEvents().size());
+        assertEquals(3, listAppender.getEvents().size(), "Incorrect number of events");
     }
 
-    @Test(expected = AssertionError.class)
-    public void testAppenderAbsence() {
-        loggerContextRule.getListAppender("List1");
+    @Test
+    public void testNotListAppender() {
+        Appender appender = loggerContext.getConfiguration().getAppender("List1");
+        assertFalse(appender instanceof ListAppender);
     }
 
     @Test
     public void testListAppenderPresence() {
         // No appender until an event is routed, even thought we initialized the default route on startup.
-        Assert.assertNull(
-                "No appender control generated",
-                getRoutingAppender().getAppenders().get("Service2"));
+        assertNull(getRoutingAppender().getAppenders().get("Service2"), "No appender control generated");
     }
 
     @Test
     public void testNoPurgePolicy() {
         // No PurgePolicy in this test
-        Assert.assertNull("Unexpected PurgePolicy", getRoutingAppender().getPurgePolicy());
+        assertNull(getRoutingAppender().getPurgePolicy(), "Unexpected PurgePolicy");
     }
 
     @Test
     public void testNoRewritePolicy() {
         // No RewritePolicy in this test
-        Assert.assertNull("Unexpected RewritePolicy", getRoutingAppender().getRewritePolicy());
+        assertNull(getRoutingAppender().getRewritePolicy(), "Unexpected RewritePolicy");
     }
 
     @Test
     public void testRoutingAppenderDefaultRouteKey() {
         final RoutingAppender routingAppender = getRoutingAppender();
-        Assert.assertNotNull(routingAppender.getDefaultRouteScript());
-        Assert.assertNotNull(routingAppender.getDefaultRoute());
+        assertNotNull(routingAppender.getDefaultRouteScript());
+        assertNotNull(routingAppender.getDefaultRoute());
         assertEquals("Service2", routingAppender.getDefaultRoute().getKey());
     }
 
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/JsonRoutingAppender2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/JsonRoutingAppender2Test.java
index f57db40117..3bc8dd7b47 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/JsonRoutingAppender2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/JsonRoutingAppender2Test.java
@@ -16,42 +16,42 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.List;
 import org.apache.logging.log4j.EventLogger;
 import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.core.test.junit.CleanFiles;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
  */
 public class JsonRoutingAppender2Test {
-    private static final String CONFIG = "log4j-routing2.json";
     private static final String LOG_FILENAME = "target/rolling1/rollingtest-Unknown.log";
 
-    private final LoggerContextRule loggerContextRule = new LoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain rules = loggerContextRule.withCleanFilesRule(LOG_FILENAME);
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(false, true, 10, LOG_FILENAME);
 
     @Test
-    public void routingTest() {
+    @LoggerContextSource("log4j-routing2.json")
+    public void routingTest(final LoggerContext loggerContext) {
         StructuredDataMessage msg = new StructuredDataMessage("Test", "This is a test", "Service");
         EventLogger.logEvent(msg);
-        final List<LogEvent> list = loggerContextRule.getListAppender("List").getEvents();
-        assertNotNull("No events generated", list);
-        assertEquals("Incorrect number of events. Expected 1, got " + list.size(), 1, list.size());
+        final ListAppender app = loggerContext.getConfiguration().getAppender("List");
+        final List<LogEvent> list = app.getEvents();
+        assertNotNull(list, "No events generated");
+        assertTrue(list.size() == 1, "Incorrect number of events. Expected 1, got " + list.size());
         msg = new StructuredDataMessage("Test", "This is a test", "Unknown");
         EventLogger.logEvent(msg);
         final File file = new File(LOG_FILENAME);
-        assertTrue("File was not created", file.exists());
+        assertTrue(file.exists(), "File was not created");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/JsonRoutingAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/JsonRoutingAppenderTest.java
index 886848078c..306d824acc 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/JsonRoutingAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/JsonRoutingAppenderTest.java
@@ -16,42 +16,42 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.List;
 import org.apache.logging.log4j.EventLogger;
 import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.core.test.junit.CleanFiles;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
  */
 public class JsonRoutingAppenderTest {
-    private static final String CONFIG = "log4j-routing.json";
     private static final String LOG_FILENAME = "target/rolling1/rollingtest-Unknown.log";
 
-    private final LoggerContextRule loggerContextRule = new LoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain rules = loggerContextRule.withCleanFilesRule(LOG_FILENAME);
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(false, true, 10, LOG_FILENAME);
 
     @Test
-    public void routingTest() {
+    @LoggerContextSource("log4j-routing.json")
+    public void routingTest(final LoggerContext loggerContext) {
         StructuredDataMessage msg = new StructuredDataMessage("Test", "This is a test", "Service");
         EventLogger.logEvent(msg);
-        final List<LogEvent> list = loggerContextRule.getListAppender("List").getEvents();
-        assertNotNull("No events generated", list);
-        assertEquals("Incorrect number of events. Expected 1, got " + list.size(), 1, list.size());
+        final ListAppender app = loggerContext.getConfiguration().getAppender("List");
+        final List<LogEvent> list = app.getEvents();
+        assertNotNull(list, "No events generated");
+        assertTrue(list.size() == 1, "Incorrect number of events. Expected 1, got " + list.size());
         msg = new StructuredDataMessage("Test", "This is a test", "Unknown");
         EventLogger.logEvent(msg);
         final File file = new File(LOG_FILENAME);
-        assertTrue("File was not created", file.exists());
+        assertTrue(file.exists(), "File was not created");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/PropertiesRoutingAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/PropertiesRoutingAppenderTest.java
index 76c68ed784..e453374162 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/PropertiesRoutingAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/PropertiesRoutingAppenderTest.java
@@ -16,48 +16,51 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.List;
 import org.apache.logging.log4j.EventLogger;
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.CleanFiles;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
  */
+@LoggerContextSource("log4j-routing.properties")
 public class PropertiesRoutingAppenderTest {
-    private static final String CONFIG = "log4j-routing.properties";
     private static final String UNKNOWN_LOG_FILE = "target/rolling1/rollingtestProps-Unknown.log";
     private static final String ALERT_LOG_FILE = "target/routing1/routingtestProps-Alert.log";
     private static final String ACTIVITY_LOG_FILE = "target/routing1/routingtestProps-Activity.log";
 
     private ListAppender app;
+    private LoggerContext context = null;
 
-    private final LoggerContextRule loggerContextRule = new LoggerContextRule(CONFIG);
+    PropertiesRoutingAppenderTest(LoggerContext context) {
+        this.context = context;
+    }
 
-    @Rule
-    public RuleChain rules = loggerContextRule.withCleanFilesRule(UNKNOWN_LOG_FILE, ALERT_LOG_FILE, ACTIVITY_LOG_FILE);
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(false, true, 10, UNKNOWN_LOG_FILE, ALERT_LOG_FILE, ACTIVITY_LOG_FILE);
 
-    @Before
-    public void setUp() {
-        this.app = this.loggerContextRule.getListAppender("List");
+    @BeforeEach
+    public void beforeEach() throws Exception {
+        this.app = this.context.getConfiguration().getAppender("List");
     }
 
-    @After
-    public void tearDown() {
+    @AfterEach
+    public void tearDown() throws Exception {
         this.app.clear();
-        this.loggerContextRule.getLoggerContext().stop();
+        this.context.stop();
     }
 
     @Test
@@ -65,15 +68,15 @@ public class PropertiesRoutingAppenderTest {
         StructuredDataMessage msg = new StructuredDataMessage("Test", "This is a test", "Service");
         EventLogger.logEvent(msg);
         final List<LogEvent> list = app.getEvents();
-        assertNotNull("No events generated", list);
-        assertEquals("Incorrect number of events. Expected 1, got " + list.size(), 1, list.size());
+        assertNotNull(list, "No events generated");
+        assertTrue(list.size() == 1, "Incorrect number of events. Expected 1, got " + list.size());
         msg = new StructuredDataMessage("Test", "This is a test", "Alert");
         EventLogger.logEvent(msg);
         File file = new File(ALERT_LOG_FILE);
-        assertTrue("Alert file was not created", file.exists());
+        assertTrue(file.exists(), "Alert file was not created");
         msg = new StructuredDataMessage("Test", "This is a test", "Activity");
         EventLogger.logEvent(msg);
         file = new File(ACTIVITY_LOG_FILE);
-        assertTrue("Activity file was not created", file.exists());
+        assertTrue(file.exists(), "Activity file was not created");
     }
 }
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/AvailablePortSystemPropertyTestRule.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderGroovyStaticVarsTest.java
similarity index 58%
rename from log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/AvailablePortSystemPropertyTestRule.java
rename to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderGroovyStaticVarsTest.java
index 45416c7924..b03c99d4a0 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/AvailablePortSystemPropertyTestRule.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderGroovyStaticVarsTest.java
@@ -14,19 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.core.test;
+package org.apache.logging.log4j.core.appender.routing;
 
-/**
- * A JUnit TestRule to discover an available port and save it in a system property. Useful for setting up tests using
- * Apache Active MQ.
- */
-public class AvailablePortSystemPropertyTestRule extends SystemPropertyTestRule {
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
 
-    public static AvailablePortSystemPropertyTestRule create(final String name) {
-        return new AvailablePortSystemPropertyTestRule(name);
-    }
+@LoggerContextSource(
+        value = "log4j-routing-script-staticvars-groovy.xml",
+        reconfigure = ReconfigurationPolicy.BEFORE_EACH)
+public class RoutesScriptAppenderGroovyStaticVarsTest extends RoutesScriptAppenderTest {
 
-    protected AvailablePortSystemPropertyTestRule(final String name) {
-        super(name, () -> Integer.toString(AvailablePortFinder.getNextAvailable()));
+    public RoutesScriptAppenderGroovyStaticVarsTest(LoggerContext context) {
+        super(context, true);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderGroovyTest.java
similarity index 59%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderGroovyTest.java
index bd1990746e..f036479177 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderGroovyTest.java
@@ -14,21 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.core.appender.db.jdbc;
+package org.apache.logging.log4j.core.appender.routing;
 
-import java.io.IOException;
-import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
 
-/**
- * Abstracts H2 test clean up.
- */
-public abstract class AbstractH2Test {
+@LoggerContextSource(value = "log4j-routing-routes-script-groovy.xml", reconfigure = ReconfigurationPolicy.BEFORE_EACH)
+public class RoutesScriptAppenderGroovyTest extends RoutesScriptAppenderTest {
 
-    @AfterClass
-    @BeforeClass
-    public static void classDeleteDir() throws IOException {
-        JdbcH2TestHelper.deleteDir();
+    public RoutesScriptAppenderGroovyTest(LoggerContext context) {
+        super(context, false);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderJavaScriptStaticVarsTest.java
similarity index 57%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderJavaScriptStaticVarsTest.java
index bd1990746e..5f57331722 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderJavaScriptStaticVarsTest.java
@@ -14,21 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.core.appender.db.jdbc;
+package org.apache.logging.log4j.core.appender.routing;
 
-import java.io.IOException;
-import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
 
-/**
- * Abstracts H2 test clean up.
- */
-public abstract class AbstractH2Test {
+@LoggerContextSource(
+        value = "log4j-routing-script-staticvars-javascript.xml",
+        reconfigure = ReconfigurationPolicy.BEFORE_EACH)
+public class RoutesScriptAppenderJavaScriptStaticVarsTest extends RoutesScriptAppenderTest {
 
-    @AfterClass
-    @BeforeClass
-    public static void classDeleteDir() throws IOException {
-        JdbcH2TestHelper.deleteDir();
+    public RoutesScriptAppenderJavaScriptStaticVarsTest(LoggerContext context) {
+        super(context, true);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderJavaScriptTest.java
similarity index 58%
copy from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
copy to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderJavaScriptTest.java
index bd1990746e..cdaa56e02a 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractH2Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderJavaScriptTest.java
@@ -14,21 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.core.appender.db.jdbc;
+package org.apache.logging.log4j.core.appender.routing;
 
-import java.io.IOException;
-import org.apache.logging.log4j.core.test.appender.db.jdbc.JdbcH2TestHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
 
-/**
- * Abstracts H2 test clean up.
- */
-public abstract class AbstractH2Test {
+@LoggerContextSource(
+        value = "log4j-routing-routes-script-javascript.xml",
+        reconfigure = ReconfigurationPolicy.BEFORE_EACH)
+public class RoutesScriptAppenderJavaScriptTest extends RoutesScriptAppenderTest {
 
-    @AfterClass
-    @BeforeClass
-    public static void classDeleteDir() throws IOException {
-        JdbcH2TestHelper.deleteDir();
+    public RoutesScriptAppenderJavaScriptTest(LoggerContext context) {
+        super(context, false);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderTest.java
index 4b838011aa..fbc03ebe13 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderTest.java
@@ -16,8 +16,11 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -25,50 +28,31 @@ import java.util.concurrent.ConcurrentMap;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.MarkerManager;
+import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.AppenderControl;
 import org.apache.logging.log4j.core.impl.DefaultLogEventFactory;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.categories.Scripts;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
 import org.apache.logging.log4j.core.util.Constants;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-@Category(Scripts.Groovy.class) // technically only half of these tests require groovy
-public class RoutesScriptAppenderTest {
-
-    @Parameterized.Parameters(name = "{0} {1}")
-    public static Object[][] getParameters() {
-        // @formatter:off
-        return new Object[][] {
-            {"log4j-routing-routes-script-groovy.xml", false},
-            {"log4j-routing-routes-script-javascript.xml", false},
-            {"log4j-routing-script-staticvars-javascript.xml", true},
-            {"log4j-routing-script-staticvars-groovy.xml", true},
-        };
-        // @formatter:on
-    }
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+@Tag("Scripts.Groovy") // technically only half of these tests require groovy
+public abstract class RoutesScriptAppenderTest {
 
-    @BeforeClass
+    @BeforeAll
     public static void beforeClass() {
         System.setProperty(Constants.SCRIPT_LANGUAGES, "Groovy, JavaScript");
     }
 
-    @Rule
-    public final LoggerContextRule loggerContextRule;
-
+    private LoggerContext loggerContext;
     private final boolean expectBindingEntries;
 
-    public RoutesScriptAppenderTest(final String configLocation, final boolean expectBindingEntries) {
-        this.loggerContextRule = new LoggerContextRule(configLocation);
+    public RoutesScriptAppenderTest(LoggerContext loggerContext, final boolean expectBindingEntries) {
+        this.loggerContext = loggerContext;
         this.expectBindingEntries = expectBindingEntries;
     }
 
@@ -76,60 +60,59 @@ public class RoutesScriptAppenderTest {
         final RoutingAppender routingAppender = getRoutingAppender();
         final ConcurrentMap<Object, Object> map = routingAppender.getScriptStaticVariables();
         if (expectBindingEntries) {
-            assertEquals("TestValue2", map.get("TestKey"));
-            assertEquals("HEXDUMP", map.get("MarkerName"));
+            assertEquals(map.get("TestKey"), "TestValue2");
+            assertEquals(map.get("MarkerName"), "HEXDUMP");
         }
     }
 
     private ListAppender getListAppender() {
         final String key = "Service2";
         final RoutingAppender routingAppender = getRoutingAppender();
-        Assert.assertTrue(routingAppender.isStarted());
+        assertTrue(routingAppender.isStarted());
         final Map<String, AppenderControl> appenders = routingAppender.getAppenders();
         final AppenderControl appenderControl = appenders.get(key);
-        assertNotNull("No appender control generated for '" + key + "'; appenders = " + appenders, appenderControl);
+        assertNotNull(appenderControl, "No appender control generated for '" + key + "'; appenders = " + appenders);
         return (ListAppender) appenderControl.getAppender();
     }
 
     private RoutingAppender getRoutingAppender() {
-        return loggerContextRule.getRequiredAppender("Routing", RoutingAppender.class);
+        return (RoutingAppender) loggerContext.getConfiguration().getAppender("Routing");
     }
 
     private void logAndCheck() {
         final Marker marker = MarkerManager.getMarker("HEXDUMP");
-        final Logger logger = loggerContextRule.getLogger(RoutesScriptAppenderTest.class);
+        final Logger logger = (Logger) loggerContext.getLogger(RoutesScriptAppenderTest.class);
         logger.error("Hello");
         final ListAppender listAppender = getListAppender();
-        assertEquals("Incorrect number of events", 1, listAppender.getEvents().size());
+        assertEquals(1, listAppender.getEvents().size(), "Incorrect number of events");
         logger.error("World");
-        assertEquals("Incorrect number of events", 2, listAppender.getEvents().size());
+        assertEquals(2, listAppender.getEvents().size(), "Incorrect number of events");
         logger.error(marker, "DEADBEEF");
-        assertEquals("Incorrect number of events", 3, listAppender.getEvents().size());
+        assertEquals(3, listAppender.getEvents().size(), "Incorrect number of events");
     }
 
-    @Test(expected = AssertionError.class)
-    public void testAppenderAbsence() {
-        loggerContextRule.getListAppender("List1");
+    @Test
+    public void testNotListAppender() {
+        Appender appender = loggerContext.getConfiguration().getAppender("List1");
+        assertFalse(appender instanceof ListAppender);
     }
 
     @Test
     public void testListAppenderPresence() {
         // No appender until an event is routed, even thought we initialized the default route on startup.
-        Assert.assertNull(
-                "No appender control generated",
-                getRoutingAppender().getAppenders().get("Service2"));
+        assertNull(getRoutingAppender().getAppenders().get("Service2"), "No appender control generated");
     }
 
     @Test
     public void testNoPurgePolicy() {
         // No PurgePolicy in this test
-        Assert.assertNull("Unexpected PurgePolicy", getRoutingAppender().getPurgePolicy());
+        assertNull(getRoutingAppender().getPurgePolicy(), "Unexpected PurgePolicy");
     }
 
     @Test
     public void testNoRewritePolicy() {
         // No RewritePolicy in this test
-        Assert.assertNull("Unexpected RewritePolicy", getRoutingAppender().getRewritePolicy());
+        assertNull(getRoutingAppender().getRewritePolicy(), "Unexpected RewritePolicy");
     }
 
     @Test
@@ -138,8 +121,8 @@ public class RoutesScriptAppenderTest {
         assertEquals(expectBindingEntries, routingAppender.getDefaultRouteScript() != null);
         assertEquals(expectBindingEntries, routingAppender.getDefaultRoute() != null);
         final Routes routes = routingAppender.getRoutes();
-        Assert.assertNotNull(routes);
-        Assert.assertNotNull(routes.getPatternScript());
+        assertNotNull(routes);
+        assertNotNull(routes.getPatternScript());
         final LogEvent logEvent =
                 DefaultLogEventFactory.getInstance().createEvent("", null, "", Level.ERROR, null, null, null);
         assertEquals("Service2", routes.getPattern(logEvent, new ConcurrentHashMap<>()));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender2767Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender2767Test.java
index 6366678898..879c6a79ff 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender2767Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender2767Test.java
@@ -16,40 +16,41 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.nio.file.Files;
 import java.util.List;
 import java.util.stream.Collectors;
 import org.apache.logging.log4j.EventLogger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFiles;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
  */
+@LoggerContextSource("log4j-routing-2767.xml")
 public class RoutingAppender2767Test {
-    private static final String CONFIG = "log4j-routing-2767.xml";
     private static final String ACTIVITY_LOG_FILE = "target/routing1/routingtest-Service.log";
 
-    private final LoggerContextRule loggerContextRule = new LoggerContextRule(CONFIG);
+    private LoggerContext context = null;
 
-    @Rule
-    public RuleChain rules = loggerContextRule.withCleanFilesRule(ACTIVITY_LOG_FILE);
+    RoutingAppender2767Test(LoggerContext context) {
+        this.context = context;
+    }
 
-    @Before
-    public void setUp() {}
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(false, true, 10, ACTIVITY_LOG_FILE);
 
-    @After
-    public void tearDown() {
-        this.loggerContextRule.getLoggerContext().stop();
+    @AfterEach
+    public void tearDown() throws Exception {
+        this.context.stop();
     }
 
     @Test
@@ -57,9 +58,9 @@ public class RoutingAppender2767Test {
         final StructuredDataMessage msg = new StructuredDataMessage("Test", "This is a test", "Service");
         EventLogger.logEvent(msg);
         final File file = new File(ACTIVITY_LOG_FILE);
-        assertTrue("Activity file was not created", file.exists());
+        assertTrue(file.exists(), "Activity file was not created");
         final List<String> lines = Files.lines(file.toPath()).collect(Collectors.toList());
-        assertEquals("Incorrect number of lines", 1, lines.size());
-        assertTrue("Incorrect content", lines.get(0).contains("This is a test"));
+        assertEquals(1, lines.size(), "Incorrect number of lines");
+        assertTrue(lines.get(0).contains("This is a test"), "Incorrect content");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender3350Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender3350Test.java
index cbacf056b8..709658e10c 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender3350Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender3350Test.java
@@ -16,7 +16,7 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -26,32 +26,37 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.CleanFiles;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.message.StringMapMessage;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
+@LoggerContextSource("log4j-routing3350.xml")
 public class RoutingAppender3350Test {
-    private static final String CONFIG = "log4j-routing3350.xml";
     private static final String LOG_FILE = "target/tmp/test.log";
 
-    private final LoggerContextRule loggerContextRule = new LoggerContextRule(CONFIG);
+    private LoggerContext context = null;
 
-    @Rule
-    public RuleChain rules = loggerContextRule.withCleanFilesRule(LOG_FILE);
+    RoutingAppender3350Test(LoggerContext context) {
+        this.context = context;
+    }
+
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(false, true, 10, LOG_FILE);
 
-    @After
-    public void tearDown() {
-        this.loggerContextRule.getLoggerContext().stop();
+    @AfterEach
+    public void tearDown() throws Exception {
+        this.context.stop();
     }
 
     @Test
-    public void routingTest() throws IOException {
+    public void routingTest(final LoggerContext loggerContext) throws IOException {
         final String expected = "expectedValue";
         final StringMapMessage message = new StringMapMessage().with("data", expected);
-        final Logger logger = loggerContextRule.getLoggerContext().getLogger(getClass());
+        final Logger logger = loggerContext.getLogger(getClass());
         logger.error(message);
         final File file = new File(LOG_FILE);
         try (final InputStream inputStream = new FileInputStream(file);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderKeyLookupEvaluationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderKeyLookupEvaluationTest.java
index e44ffc0eae..18c025f835 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderKeyLookupEvaluationTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderKeyLookupEvaluationTest.java
@@ -16,59 +16,54 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.ThreadContext;
-import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Named;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 public class RoutingAppenderKeyLookupEvaluationTest {
-    private static final String CONFIG = "log4j-routing-lookup.xml";
-
     private static final String KEY = "user";
-    private ListAppender app;
-
-    @Rule
-    public final LoggerContextRule loggerContextRule = new LoggerContextRule(CONFIG);
 
-    @Before
-    public void setUp() {
+    @BeforeEach
+    public void setUp() throws Exception {
         ThreadContext.remove(KEY);
-        this.app = this.loggerContextRule.getListAppender("List");
     }
 
-    @After
-    public void tearDown() {
-        this.app.clear();
-        this.loggerContextRule.getLoggerContext().stop();
+    @AfterEach
+    public void tearDown() throws Exception {
         ThreadContext.remove(KEY);
     }
 
     @Test
-    public void testRoutingNoUser() {
-        final Logger logger = loggerContextRule.getLogger(getClass());
+    @LoggerContextSource("log4j-routing-lookup.xml")
+    public void testRoutingNoUser(final LoggerContext loggerContext, @Named("List") final ListAppender app) {
+        final Logger logger = loggerContext.getLogger(getClass());
         logger.warn("no user");
         final String message = app.getMessages().get(0);
         assertEquals("WARN ${ctx:user} no user", message);
     }
 
     @Test
-    public void testRoutingDoesNotMatchRoute() {
-        final Logger logger = loggerContextRule.getLogger(getClass());
+    @LoggerContextSource("log4j-routing-lookup.xml")
+    public void testRoutingDoesNotMatchRoute(final LoggerContext loggerContext, @Named("List") final ListAppender app) {
+        final Logger logger = loggerContext.getLogger(getClass());
         ThreadContext.put(KEY, "noRouteExists");
         logger.warn("unmatched user");
         assertTrue(app.getMessages().isEmpty());
     }
 
     @Test
-    public void testRoutingContainsLookup() {
-        final Logger logger = loggerContextRule.getLogger(getClass());
+    @LoggerContextSource("log4j-routing-lookup.xml")
+    public void testRoutingContainsLookup(final LoggerContext loggerContext, @Named("List") final ListAppender app) {
+        final Logger logger = loggerContext.getLogger(getClass());
         ThreadContext.put(KEY, "${java:version}");
         logger.warn("naughty user");
         final String message = app.getMessages().get(0);
@@ -76,8 +71,10 @@ public class RoutingAppenderKeyLookupEvaluationTest {
     }
 
     @Test
-    public void testRoutingMatchesEscapedLookup() {
-        final Logger logger = loggerContextRule.getLogger(getClass());
+    @LoggerContextSource("log4j-routing-lookup.xml")
+    public void testRoutingMatchesEscapedLookup(
+            final LoggerContext loggerContext, @Named("List") final ListAppender app) {
+        final Logger logger = loggerContext.getLogger(getClass());
         ThreadContext.put(KEY, "${upper:name}");
         logger.warn("naughty user");
         final String message = app.getMessages().get(0);
@@ -85,8 +82,10 @@ public class RoutingAppenderKeyLookupEvaluationTest {
     }
 
     @Test
-    public void testRoutesThemselvesNotEvaluated() {
-        final Logger logger = loggerContextRule.getLogger(getClass());
+    @LoggerContextSource("log4j-routing-lookup.xml")
+    public void testRoutesThemselvesNotEvaluated(
+            final LoggerContext loggerContext, @Named("List") final ListAppender app) {
+        final Logger logger = loggerContext.getLogger(getClass());
         ThreadContext.put(KEY, "NAME");
         logger.warn("unmatched user");
         assertTrue(app.getMessages().isEmpty());
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderTest.java
index eaaa3255e3..ee621fdfc5 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderTest.java
@@ -16,48 +16,51 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.List;
 import org.apache.logging.log4j.EventLogger;
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.CleanFiles;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
  */
+@LoggerContextSource("log4j-routing.xml")
 public class RoutingAppenderTest {
-    private static final String CONFIG = "log4j-routing.xml";
     private static final String UNKNOWN_LOG_FILE = "target/rolling1/rollingtest-Unknown.log";
     private static final String ALERT_LOG_FILE = "target/routing1/routingtest-Alert.log";
     private static final String ACTIVITY_LOG_FILE = "target/routing1/routingtest-Activity.log";
 
     private ListAppender app;
+    private LoggerContext context = null;
 
-    private final LoggerContextRule loggerContextRule = new LoggerContextRule(CONFIG);
+    RoutingAppenderTest(LoggerContext context) {
+        this.context = context;
+    }
 
-    @Rule
-    public RuleChain rules = loggerContextRule.withCleanFilesRule(UNKNOWN_LOG_FILE, ALERT_LOG_FILE, ACTIVITY_LOG_FILE);
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(false, true, 10, UNKNOWN_LOG_FILE, ALERT_LOG_FILE, ACTIVITY_LOG_FILE);
 
-    @Before
-    public void setUp() {
-        this.app = this.loggerContextRule.getListAppender("List");
+    @BeforeEach
+    public void beforeEach() {
+        this.app = this.context.getConfiguration().getAppender("List");
     }
 
-    @After
-    public void tearDown() {
+    @AfterEach
+    public void tearDown() throws Exception {
         this.app.clear();
-        this.loggerContextRule.getLoggerContext().stop();
+        this.context.stop();
     }
 
     @Test
@@ -65,15 +68,15 @@ public class RoutingAppenderTest {
         StructuredDataMessage msg = new StructuredDataMessage("Test", "This is a test", "Service");
         EventLogger.logEvent(msg);
         final List<LogEvent> list = app.getEvents();
-        assertNotNull("No events generated", list);
-        assertEquals("Incorrect number of events. Expected 1, got " + list.size(), 1, list.size());
+        assertNotNull(list, "No events generated");
+        assertTrue(list.size() == 1, "Incorrect number of events. Expected 1, got " + list.size());
         msg = new StructuredDataMessage("Test", "This is a test", "Alert");
         EventLogger.logEvent(msg);
         File file = new File(ALERT_LOG_FILE);
-        assertTrue("Alert file was not created", file.exists());
+        assertTrue(file.exists(), "Alert file was not created");
         msg = new StructuredDataMessage("Test", "This is a test", "Activity");
         EventLogger.logEvent(msg);
         file = new File(ACTIVITY_LOG_FILE);
-        assertTrue("Activity file was not created", file.exists());
+        assertTrue(file.exists(), "Activity file was not created");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java
index 0d7f8d8300..e4421d422b 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java
@@ -16,9 +16,8 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.Collections;
@@ -29,13 +28,12 @@ import javax.naming.NamingException;
 import org.apache.logging.log4j.EventLogger;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
 import org.apache.logging.log4j.core.test.junit.JndiRule;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Named;
 import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * RoutingAppenderWithJndiTest
@@ -43,14 +41,9 @@ import org.junit.rules.RuleChain;
 public class RoutingAppenderWithJndiTest {
 
     public static final String JNDI_CONTEXT_NAME = "java:comp/env/logging/context-name";
-    private ListAppender listAppender1;
-    private ListAppender listAppender2;
 
-    public static LoggerContextRule loggerContextRule = new LoggerContextRule("log4j-routing-by-jndi.xml");
-
-    @ClassRule
-    public static RuleChain rules =
-            RuleChain.outerRule(new JndiRule(initBindings())).around(loggerContextRule);
+    @RegisterExtension
+    private JndiRule jndiRule = new JndiRule(initBindings());
 
     private static Map<String, Object> initBindings() {
         System.setProperty("log4j2.enableJndiLookup", "true");
@@ -59,14 +52,9 @@ public class RoutingAppenderWithJndiTest {
         return Collections.emptyMap();
     }
 
-    @Before
-    public void before() {
-        listAppender1 = RoutingAppenderWithJndiTest.loggerContextRule.getListAppender("List1");
-        listAppender2 = RoutingAppenderWithJndiTest.loggerContextRule.getListAppender("List2");
-    }
-
-    @After
-    public void after() {
+    @AfterEach
+    public void after(
+            @Named("List1") final ListAppender listAppender1, @Named("List2") final ListAppender listAppender2) {
         if (listAppender1 != null) {
             listAppender1.clear();
         }
@@ -76,14 +64,17 @@ public class RoutingAppenderWithJndiTest {
     }
 
     @Test
+    @LoggerContextSource("log4j-routing-by-jndi.xml")
     @SuppressWarnings("BanJNDI")
-    public void routingTest() throws NamingException {
+    public void routingTest(
+            @Named("List1") final ListAppender listAppender1, @Named("List2") final ListAppender listAppender2)
+            throws NamingException {
         // default route when there's no jndi resource
         StructuredDataMessage msg =
                 new StructuredDataMessage("Test", "This is a message from unknown context", "Context");
         EventLogger.logEvent(msg);
         final File defaultLogFile = new File("target/routingbyjndi/routingbyjnditest-unknown.log");
-        assertTrue("The default log file was not created", defaultLogFile.exists());
+        assertTrue(defaultLogFile.exists(), "The default log file was not created");
 
         // now set jndi resource to Application1
         final Context context = new InitialContext();
@@ -91,43 +82,38 @@ public class RoutingAppenderWithJndiTest {
 
         msg = new StructuredDataMessage("Test", "This is a message from Application1", "Context");
         EventLogger.logEvent(msg);
-        assertNotNull("No events generated", listAppender1.getEvents());
-        assertEquals(
+        assertNotNull(listAppender1.getEvents(), "No events generated");
+        assertTrue(
+                listAppender1.getEvents().size() == 1,
                 "Incorrect number of events. Expected 1, got "
-                        + listAppender1.getEvents().size(),
-                1,
-                listAppender1.getEvents().size());
+                        + listAppender1.getEvents().size());
 
         // now set jndi resource to Application2
         context.rebind(JNDI_CONTEXT_NAME, "Application2");
 
         msg = new StructuredDataMessage("Test", "This is a message from Application2", "Context");
         EventLogger.logEvent(msg);
-        assertNotNull("No events generated", listAppender2.getEvents());
-        assertEquals(
+        assertNotNull(listAppender2.getEvents(), "No events generated");
+        assertTrue(
+                listAppender2.getEvents().size() == 1,
                 "Incorrect number of events. Expected 1, got "
-                        + listAppender2.getEvents().size(),
-                1,
-                listAppender2.getEvents().size());
-        assertEquals(
+                        + listAppender2.getEvents().size());
+        assertTrue(
+                listAppender1.getEvents().size() == 1,
                 "Incorrect number of events. Expected 1, got "
-                        + listAppender1.getEvents().size(),
-                1,
-                listAppender1.getEvents().size());
+                        + listAppender1.getEvents().size());
 
         msg = new StructuredDataMessage("Test", "This is another message from Application2", "Context");
         EventLogger.logEvent(msg);
-        assertNotNull("No events generated", listAppender2.getEvents());
-        assertEquals(
+        assertNotNull(listAppender2.getEvents(), "No events generated");
+        assertTrue(
+                listAppender2.getEvents().size() == 2,
                 "Incorrect number of events. Expected 2, got "
-                        + listAppender2.getEvents().size(),
-                2,
-                listAppender2.getEvents().size());
-        assertEquals(
+                        + listAppender2.getEvents().size());
+        assertTrue(
+                listAppender1.getEvents().size() == 1,
                 "Incorrect number of events. Expected 1, got "
-                        + listAppender1.getEvents().size(),
-                1,
-                listAppender1.getEvents().size());
+                        + listAppender1.getEvents().size());
 
         // now set jndi resource to Application3.
         // The context name, 'Application3', will be used as log file name by the default route.
@@ -135,7 +121,7 @@ public class RoutingAppenderWithJndiTest {
         msg = new StructuredDataMessage("Test", "This is a message from Application3", "Context");
         EventLogger.logEvent(msg);
         final File application3LogFile = new File("target/routingbyjndi/routingbyjnditest-Application3.log");
-        assertTrue("The Application3 log file was not created", application3LogFile.exists());
+        assertTrue(application3LogFile.exists(), "The Application3 log file was not created");
 
         // now set jndi resource to Application4
         // The context name, 'Application4', will be used as log file name by the default route.
@@ -143,6 +129,6 @@ public class RoutingAppenderWithJndiTest {
         msg = new StructuredDataMessage("Test", "This is a message from Application4", "Context");
         EventLogger.logEvent(msg);
         final File application4LogFile = new File("target/routingbyjndi/routingbyjnditest-Application4.log");
-        assertTrue("The Application3 log file was not created", application4LogFile.exists());
+        assertTrue(application4LogFile.exists(), "The Application3 log file was not created");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithPurgingTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithPurgingTest.java
index 9d40d070e2..883759890c 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithPurgingTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithPurgingTest.java
@@ -16,10 +16,10 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.HashSet;
@@ -27,20 +27,20 @@ import java.util.List;
 import java.util.Set;
 import org.apache.logging.log4j.EventLogger;
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.CleanFiles;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Named;
 import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Tests Routing appender purge facilities
  */
 public class RoutingAppenderWithPurgingTest {
-    private static final String CONFIG = "log4j-routing-purge.xml";
     private static final String IDLE_LOG_FILE1 = "target/routing-purge-idle/routingtest-1.log";
     private static final String IDLE_LOG_FILE2 = "target/routing-purge-idle/routingtest-2.log";
     private static final String IDLE_LOG_FILE3 = "target/routing-purge-idle/routingtest-3.log";
@@ -48,41 +48,34 @@ public class RoutingAppenderWithPurgingTest {
     private static final String MANUAL_LOG_FILE2 = "target/routing-purge-manual/routingtest-2.log";
     private static final String MANUAL_LOG_FILE3 = "target/routing-purge-manual/routingtest-3.log";
 
-    private ListAppender app;
-    private RoutingAppender routingAppenderIdle;
-    private RoutingAppender routingAppenderIdleWithHangingAppender;
-    private RoutingAppender routingAppenderManual;
-
-    private final LoggerContextRule loggerContextRule = new LoggerContextRule(CONFIG);
-
-    @Rule
-    public RuleChain chain = loggerContextRule.withCleanFilesRule(
-            IDLE_LOG_FILE1, IDLE_LOG_FILE2, IDLE_LOG_FILE3, MANUAL_LOG_FILE1, MANUAL_LOG_FILE2, MANUAL_LOG_FILE3);
-
-    @Before
-    public void setUp() {
-        this.app = this.loggerContextRule.getListAppender("List");
-        this.routingAppenderIdle =
-                this.loggerContextRule.getRequiredAppender("RoutingPurgeIdle", RoutingAppender.class);
-        this.routingAppenderIdleWithHangingAppender = this.loggerContextRule.getRequiredAppender(
-                "RoutingPurgeIdleWithHangingAppender", RoutingAppender.class);
-        this.routingAppenderManual =
-                this.loggerContextRule.getRequiredAppender("RoutingPurgeManual", RoutingAppender.class);
-    }
-
-    @After
-    public void tearDown() {
-        this.app.clear();
-        this.loggerContextRule.getLoggerContext().stop();
-    }
-
-    @Test(timeout = 5000)
-    public void routingTest() throws InterruptedException {
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(
+            false,
+            true,
+            10,
+            IDLE_LOG_FILE1,
+            IDLE_LOG_FILE2,
+            IDLE_LOG_FILE3,
+            MANUAL_LOG_FILE1,
+            MANUAL_LOG_FILE2,
+            MANUAL_LOG_FILE3);
+
+    @Test
+    @Timeout(5000)
+    @LoggerContextSource("log4j-routing-purge.xml")
+    public void routingTest(
+            final LoggerContext loggerContext,
+            @Named("List") final ListAppender app,
+            @Named("RoutingPurgeIdle") final RoutingAppender routingAppenderIdle,
+            @Named("RoutingPurgeIdleWithHangingAppender") final RoutingAppender routingAppenderIdleWithHangingAppender,
+            @Named("RoutingPurgeManual") final RoutingAppender routingAppenderManual,
+            @Named("ReferencedList") final ListAppender referencedListAppender)
+            throws InterruptedException {
         StructuredDataMessage msg = new StructuredDataMessage("1", "This is a test 1", "Service");
         EventLogger.logEvent(msg);
         final List<LogEvent> list = app.getEvents();
-        assertNotNull("No events generated", list);
-        assertEquals("Incorrect number of events. Expected 1, got " + list.size(), 1, list.size());
+        assertNotNull(list, "No events generated");
+        assertTrue(list.size() == 1, "Incorrect number of events. Expected 1, got " + list.size());
         msg = new StructuredDataMessage("2", "This is a test 2", "Service");
         EventLogger.logEvent(msg);
         msg = new StructuredDataMessage("3", "This is a test 3", "Service");
@@ -95,72 +88,51 @@ public class RoutingAppenderWithPurgingTest {
         expectedAppenderKeys.add("3");
         assertEquals(expectedAppenderKeys, routingAppenderManual.getAppenders().keySet());
 
-        assertFalse(((ListAppender) loggerContextRule.getAppender("ReferencedList"))
-                .getEvents()
-                .isEmpty());
+        assertFalse(((ListAppender) referencedListAppender).getEvents().isEmpty());
 
         assertEquals(
-                "Incorrect number of appenders with IdlePurgePolicy.",
-                2,
-                routingAppenderIdle.getAppenders().size());
-        assertEquals(
-                "Incorrect number of appenders with IdlePurgePolicy with HangingAppender.",
-                2,
-                routingAppenderIdleWithHangingAppender.getAppenders().size());
+                2, routingAppenderIdle.getAppenders().size(), "Incorrect number of appenders with IdlePurgePolicy.");
         assertEquals(
-                "Incorrect number of appenders manual purge.",
                 2,
-                routingAppenderManual.getAppenders().size());
+                routingAppenderIdleWithHangingAppender.getAppenders().size(),
+                "Incorrect number of appenders with IdlePurgePolicy with HangingAppender.");
+        assertEquals(2, routingAppenderManual.getAppenders().size(), "Incorrect number of appenders manual purge.");
 
         Thread.sleep(3000);
         EventLogger.logEvent(msg);
 
         assertEquals(
-                "Incorrect number of appenders with IdlePurgePolicy.",
-                1,
-                routingAppenderIdle.getAppenders().size());
+                1, routingAppenderIdle.getAppenders().size(), "Incorrect number of appenders with IdlePurgePolicy.");
         assertEquals(
-                "Incorrect number of appenders with manual purge.",
-                2,
-                routingAppenderManual.getAppenders().size());
+                2, routingAppenderManual.getAppenders().size(), "Incorrect number of appenders with manual purge.");
 
         routingAppenderManual.deleteAppender("1");
         routingAppenderManual.deleteAppender("2");
         routingAppenderManual.deleteAppender("3");
 
         assertEquals(
-                "Incorrect number of appenders with IdlePurgePolicy.",
-                1,
-                routingAppenderIdle.getAppenders().size());
+                1, routingAppenderIdle.getAppenders().size(), "Incorrect number of appenders with IdlePurgePolicy.");
         assertEquals(
-                "Incorrect number of appenders with manual purge.",
-                0,
-                routingAppenderManual.getAppenders().size());
+                0, routingAppenderManual.getAppenders().size(), "Incorrect number of appenders with manual purge.");
 
-        assertFalse(
-                "Reference based routes should not be stoppable",
-                loggerContextRule.getAppender("ReferencedList").isStopped());
+        assertFalse(referencedListAppender.isStopped(), "Reference based routes should not be stoppable");
 
         msg = new StructuredDataMessage("5", "This is a test 5", "Service");
         EventLogger.logEvent(msg);
 
         assertEquals(
-                "Incorrect number of appenders with manual purge.",
-                1,
-                routingAppenderManual.getAppenders().size());
+                1, routingAppenderManual.getAppenders().size(), "Incorrect number of appenders with manual purge.");
 
         routingAppenderManual.deleteAppender("5");
         routingAppenderManual.deleteAppender("5");
 
         assertEquals(
-                "Incorrect number of appenders with manual purge.",
-                0,
-                routingAppenderManual.getAppenders().size());
+                0, routingAppenderManual.getAppenders().size(), "Incorrect number of appenders with manual purge.");
     }
 
     private void assertFileExistance(final String... files) {
         for (final String file : files) {
-            assertTrue("File should exist - " + file + " file ", new File(file).exists());
+            assertTrue(new File(file).exists(), "File should exist - " + file + " file ");
         }
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingDefaultAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingDefaultAppenderTest.java
index 91eca1321f..33403549bd 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingDefaultAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingDefaultAppenderTest.java
@@ -16,19 +16,20 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
 import java.util.List;
 import org.apache.logging.log4j.EventLogger;
 import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.core.test.junit.CleanFiles;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  *
@@ -36,21 +37,21 @@ import org.junit.rules.RuleChain;
 public class RoutingDefaultAppenderTest {
     private static final String LOG_FILE = "target/routing1/routingtest.log";
 
-    private final LoggerContextRule loggerContextRule = new LoggerContextRule("log4j-routing3.xml");
-
-    @Rule
-    public RuleChain rules = loggerContextRule.withCleanFilesRule(LOG_FILE);
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(false, true, 10, LOG_FILE);
 
     @Test
-    public void routingTest() {
+    @LoggerContextSource("log4j-routing3.xml")
+    public void routingTest(final LoggerContext loggerContext) {
         StructuredDataMessage msg = new StructuredDataMessage("Test", "This is a test", "Service");
         EventLogger.logEvent(msg);
-        final List<LogEvent> list = loggerContextRule.getListAppender("List").getEvents();
-        assertNotNull("No events generated", list);
-        assertEquals("Incorrect number of events. Expected 1, got " + list.size(), 1, list.size());
+        final ListAppender app = loggerContext.getConfiguration().getAppender("List");
+        final List<LogEvent> list = app.getEvents();
+        assertNotNull(list, "No events generated");
+        assertTrue(list.size() == 1, "Incorrect number of events. Expected 1, got " + list.size());
         msg = new StructuredDataMessage("Test", "This is a test", "Alert");
         EventLogger.logEvent(msg);
         final File file = new File(LOG_FILE);
-        assertTrue("Alert file was not created", file.exists());
+        assertTrue(file.exists(), "Alert file was not created");
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncLoggerConfigTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncLoggerConfigTest.java
index 420406d965..9f2a6ec306 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncLoggerConfigTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggersWithAsyncLoggerConfigTest.java
@@ -16,39 +16,39 @@
  */
 package org.apache.logging.log4j.core.async;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import java.util.List;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.categories.AsyncLoggers;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Tags;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
 
-@Category(AsyncLoggers.class)
+@Tag(Tags.ASYNC_LOGGERS)
 public class AsyncLoggersWithAsyncLoggerConfigTest {
 
-    @ClassRule
-    public static LoggerContextRule context =
-            new LoggerContextRule("AsyncLoggersWithAsyncLoggerConfigTest.xml", AsyncLoggerContextSelector.class);
-
     @Test
-    public void testLoggingWorks() throws Exception {
+    @LoggerContextSource("AsyncLoggersWithAsyncLoggerConfigTest.xml")
+    public void testLoggingWorks(LoggerContext context) throws Exception {
         final Logger logger = LogManager.getLogger();
         logger.error("This is a test");
         logger.warn("Hello world!");
         Thread.sleep(100);
-        final List<String> list = context.getListAppender("List").getMessages();
-        assertNotNull("No events generated", list);
-        assertEquals("Incorrect number of events. Expected 2, got " + list.size(), 2, list.size());
+        final ListAppender listAppender = context.getConfiguration().getAppender("List");
+        final List<String> list = listAppender.getMessages();
+
+        assertNotNull(list, "No events generated");
+        assertEquals(2, list.size(), "Incorrect number of events. Expected 2, got " + list.size());
         String msg = list.get(0);
         String expected = getClass().getName() + " This is a test";
-        assertEquals("Expected " + expected + ", Actual " + msg, expected, msg);
+        assertEquals(expected, msg, "Expected " + expected + ", Actual " + msg);
         msg = list.get(1);
         expected = getClass().getName() + " Hello world!";
-        assertEquals("Expected " + expected + ", Actual " + msg, expected, msg);
+        assertEquals(expected, msg, "Expected " + expected + ", Actual " + msg);
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncRootReloadTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncRootReloadTest.java
index 7c97428c0a..ec70e915ff 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncRootReloadTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncRootReloadTest.java
@@ -21,30 +21,29 @@ import java.net.URISyntaxException;
 import java.net.URL;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.categories.AsyncLoggers;
 import org.apache.logging.log4j.core.test.junit.CleanFiles;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Tags;
 import org.apache.logging.log4j.core.util.FileUtils;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 /**
  * Tests LOG4J2-807.
  */
-@Category(AsyncLoggers.class)
+@Tag(Tags.ASYNC_LOGGERS)
 public class AsyncRootReloadTest {
 
     private static final String ISSUE = "LOG4J2-807";
     private static final String ISSUE_CONFIG = ISSUE + ".xml";
     private static final String LOG = "target/" + ISSUE + ".log";
-    private static final String RESOURCE = "classpath:" + ISSUE_CONFIG;
 
-    @ClassRule
-    public static RuleChain rules = RuleChain.outerRule(new CleanFiles(LOG)).around(new LoggerContextRule(RESOURCE));
+    @RegisterExtension
+    CleanFiles cleanFiles = new CleanFiles(false, true, 10, LOG);
 
     @Test
+    @LoggerContextSource("classpath:LOG4J2-807.xml")
     public void testLog4j2_807() throws InterruptedException, URISyntaxException {
         final URL url = AsyncRootReloadTest.class.getResource("/" + ISSUE_CONFIG);
         final File configFile = FileUtils.fileFromUri(url.toURI());
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688AsyncTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688AsyncTest.java
index 1d72e8fc8f..a525a428d6 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688AsyncTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688AsyncTest.java
@@ -16,54 +16,49 @@
  */
 package org.apache.logging.log4j.core.async;
 
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.categories.AsyncLoggers;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Tags;
 import org.apache.logging.log4j.core.util.Constants;
 import org.apache.logging.log4j.spi.ExtendedLogger;
 import org.apache.logging.log4j.util.Strings;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
 
 /**
  * Tests LOG4J2-1688 Multiple loggings of arguments are setting these arguments to null.
  */
-@RunWith(BlockJUnit4ClassRunner.class)
-@Category(AsyncLoggers.class)
+@Tag(Tags.ASYNC_LOGGERS)
 public class Log4j2Jira1688AsyncTest {
 
-    @BeforeClass
+    private ListAppender listAppender;
+
+    @BeforeAll
     public static void beforeClass() {
         System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, AsyncLoggerContextSelector.class.getName());
         System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "log4j-list.xml");
     }
 
-    @AfterClass
+    @AfterAll
     public static void afterClass() {
         System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, Strings.EMPTY);
     }
 
-    @Rule
-    public LoggerContextRule context = new LoggerContextRule("log4j-list.xml");
-
-    private ListAppender listAppender;
-
-    @Before
-    public void before() {
-        listAppender = context.getListAppender("List");
+    @BeforeEach
+    public void before(LoggerContext context) {
+        listAppender = context.getConfiguration().getAppender("List");
     }
 
     private static Object[] createArray(final int size) {
@@ -75,7 +70,8 @@ public class Log4j2Jira1688AsyncTest {
     }
 
     @Test
-    public void testLog4j2Only() throws InterruptedException {
+    @LoggerContextSource("log4j-list.xml")
+    public void testLog4j2Only(LoggerContext context) throws InterruptedException {
         final org.apache.logging.log4j.Logger log4JLogger = LogManager.getLogger(this.getClass());
         final int limit = 11; // more than unrolled varargs
         final Object[] args = createArray(limit);
@@ -85,9 +81,9 @@ public class Log4j2Jira1688AsyncTest {
         ((ExtendedLogger) log4JLogger).logIfEnabled("test", Level.ERROR, null, "test {}", args);
 
         listAppender.countDownLatch.await(1, TimeUnit.SECONDS);
-        Assert.assertArrayEquals(Arrays.toString(args), originalArgs, args);
+        assertArrayEquals(originalArgs, args, Arrays.toString(args));
 
         ((ExtendedLogger) log4JLogger).logIfEnabled("test", Level.ERROR, null, "test {}", args);
-        Assert.assertArrayEquals(Arrays.toString(args), originalArgs, args);
+        assertArrayEquals(originalArgs, args, Arrays.toString(args));
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688Test.java
index 4e69ab7085..dff0df3c8f 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/Log4j2Jira1688Test.java
@@ -16,53 +16,48 @@
  */
 package org.apache.logging.log4j.core.async;
 
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.categories.AsyncLoggers;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.Tags;
 import org.apache.logging.log4j.core.util.Constants;
 import org.apache.logging.log4j.spi.ExtendedLogger;
 import org.apache.logging.log4j.util.Strings;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
 
 /**
  * Tests LOG4J2-1688 Multiple loggings of arguments are setting these arguments to null.
  */
-@RunWith(BlockJUnit4ClassRunner.class)
-@Category(AsyncLoggers.class)
+@Tag(Tags.ASYNC_LOGGERS)
 public class Log4j2Jira1688Test {
 
-    @BeforeClass
+    private ListAppender listAppender;
+
+    @BeforeAll
     public static void beforeClass() {
         System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "log4j-list.xml");
     }
 
-    @AfterClass
+    @AfterAll
     public static void afterClass() {
         System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, Strings.EMPTY);
     }
 
-    @Rule
-    public LoggerContextRule context = new LoggerContextRule("log4j-list.xml");
-
-    private ListAppender listAppender;
-
-    @Before
-    public void before() {
-        listAppender = context.getListAppender("List");
+    @BeforeEach
+    public void before(LoggerContext context) {
+        listAppender = context.getConfiguration().getAppender("List");
     }
 
     private static Object[] createArray(final int size) {
@@ -74,7 +69,8 @@ public class Log4j2Jira1688Test {
     }
 
     @Test
-    public void testLog4j2Only() throws InterruptedException {
+    @LoggerContextSource("log4j-list.xml")
+    public void testLog4j2Only(LoggerContext context) throws InterruptedException {
         final org.apache.logging.log4j.Logger log4JLogger = LogManager.getLogger(this.getClass());
         final int limit = 11; // more than unrolled varargs
         final Object[] args = createArray(limit);
@@ -84,9 +80,9 @@ public class Log4j2Jira1688Test {
         ((ExtendedLogger) log4JLogger).logIfEnabled("test", Level.ERROR, null, "test {}", args);
 
         listAppender.countDownLatch.await(1, TimeUnit.SECONDS);
-        Assert.assertArrayEquals(Arrays.toString(args), originalArgs, args);
+        assertArrayEquals(originalArgs, args, Arrays.toString(args));
 
         ((ExtendedLogger) log4JLogger).logIfEnabled("test", Level.ERROR, null, "test {}", args);
-        Assert.assertArrayEquals(Arrays.toString(args), originalArgs, args);
+        assertArrayEquals(originalArgs, args, Arrays.toString(args));
     }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
index 69956c1c84..f25e23d202 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
@@ -16,26 +16,23 @@
  */
 package org.apache.logging.log4j.core.config;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.util.List;
 import java.util.Map;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.ConsoleAppender;
 import org.apache.logging.log4j.core.appender.FileAppender;
 import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
 import org.apache.logging.log4j.core.filter.RegexFilter;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.apache.logging.log4j.core.util.Throwables;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.Test;
 
 public class CompositeConfigurationTest {
     /*
@@ -87,151 +84,94 @@ public class CompositeConfigurationTest {
         }
     */
     @Test
-    public void compositeLogger() {
-        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-logger.xml,log4j-comp-logger.json");
-        final Statement test = new Statement() {
-            @Override
-            public void evaluate() {
-                final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                Map<String, Appender> appendersMap = config.getLogger("cat1").getAppenders();
-                assertEquals(
-                        "Expected 2 Appender references for cat1 but got " + appendersMap.size(),
-                        2,
-                        appendersMap.size());
-                assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
-
-                final Filter loggerFilter = config.getLogger("cat1").getFilter();
-                assertTrue(loggerFilter instanceof RegexFilter);
-                assertEquals(Filter.Result.DENY, loggerFilter.getOnMatch());
-
-                appendersMap = config.getLogger("cat2").getAppenders();
-                assertEquals(
-                        "Expected 1 Appender reference for cat2 but got " + appendersMap.size(),
-                        1,
-                        appendersMap.size());
-                assertTrue(appendersMap.get("File") instanceof FileAppender);
-
-                appendersMap = config.getLogger("cat3").getAppenders();
-                assertEquals(
-                        "Expected 1 Appender reference for cat3 but got " + appendersMap.size(),
-                        1,
-                        appendersMap.size());
-                assertTrue(appendersMap.get("File") instanceof FileAppender);
-
-                appendersMap = config.getRootLogger().getAppenders();
-                assertEquals(
-                        "Expected 2 Appender references for the root logger but got " + appendersMap.size(),
-                        2,
-                        appendersMap.size());
-                assertTrue(appendersMap.get("File") instanceof FileAppender);
-                assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
-
-                assertEquals(
-                        "Expected COMPOSITE_SOURCE for composite configuration but got "
-                                + config.getConfigurationSource(),
-                        ConfigurationSource.COMPOSITE_SOURCE,
-                        config.getConfigurationSource());
-            }
-        };
-        runTest(lcr, test);
+    @LoggerContextSource("classpath:log4j-comp-logger.xml,log4j-comp-logger.json")
+    public void compositeLogger(final LoggerContext lcr) {
+        final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+        Map<String, Appender> appendersMap = config.getLogger("cat1").getAppenders();
+        assertEquals(2, appendersMap.size(), "Expected 2 Appender references for cat1 but got " + appendersMap.size());
+        assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
+
+        final Filter loggerFilter = config.getLogger("cat1").getFilter();
+        assertTrue(loggerFilter instanceof RegexFilter);
+        assertEquals(Filter.Result.DENY, loggerFilter.getOnMatch());
+
+        appendersMap = config.getLogger("cat2").getAppenders();
+        assertEquals(1, appendersMap.size(), "Expected 1 Appender reference for cat2 but got " + appendersMap.size());
+        assertTrue(appendersMap.get("File") instanceof FileAppender);
+
+        appendersMap = config.getLogger("cat3").getAppenders();
+        assertEquals(1, appendersMap.size(), "Expected 1 Appender reference for cat3 but got " + appendersMap.size());
+        assertTrue(appendersMap.get("File") instanceof FileAppender);
+
+        appendersMap = config.getRootLogger().getAppenders();
+        assertEquals(
+                2,
+                appendersMap.size(),
+                "Expected 2 Appender references for the root logger but got " + appendersMap.size());
+        assertTrue(appendersMap.get("File") instanceof FileAppender);
+        assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
+
+        assertEquals(
+                ConfigurationSource.COMPOSITE_SOURCE,
+                config.getConfigurationSource(),
+                "Expected COMPOSITE_SOURCE for composite configuration but got " + config.getConfigurationSource());
     }
 
     @Test
-    public void testAttributeCheckWhenMergingConfigurations() {
-        final LoggerContextRule lcr =
-                new LoggerContextRule("classpath:log4j-comp-root-loggers.xml,log4j-comp-logger.json");
-        final Statement test = new Statement() {
-            @Override
-            public void evaluate() {
-                try {
-                    final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                    Assert.assertNotNull(config);
-                } catch (final NullPointerException e) {
-                    fail("Should not throw NullPointerException when there are different nodes.");
-                }
-            }
-        };
-        runTest(lcr, test);
+    @LoggerContextSource("classpath:log4j-comp-root-loggers.xml,log4j-comp-logger.json")
+    public void testAttributeCheckWhenMergingConfigurations(final LoggerContext lcr) {
+        try {
+            final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+            assertNotNull(config);
+        } catch (final NullPointerException e) {
+            fail("Should not throw NullPointerException when there are different nodes.");
+        }
     }
 
     @Test
-    public void testAttributeMergeForLoggers() {
-        final LoggerContextRule lcr =
-                new LoggerContextRule("classpath:log4j-comp-logger-root.xml,log4j-comp-logger-attr-override.json");
-        final Statement test = new Statement() {
-            @Override
-            public void evaluate() {
-                final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                // Test for Root log level override
-                assertEquals(
-                        "Expected Root logger log level to be WARN",
-                        Level.WARN,
-                        config.getRootLogger().getLevel());
-
-                // Test for cat2 level override
-                final LoggerConfig cat2 = config.getLogger("cat2");
-                assertEquals("Expected cat2 log level to be INFO", Level.INFO, cat2.getLevel());
-
-                // Test for cat2 additivity override
-                assertTrue("Expected cat2 additivity to be true", cat2.isAdditive());
-
-                // Regression
-                // Check level on cat3 (not present in root config)
-                assertEquals(
-                        "Expected cat3 log level to be ERROR",
-                        Level.ERROR,
-                        config.getLogger("cat3").getLevel());
-                // Check level on cat1 (not present in overridden config)
-                assertEquals(
-                        "Expected cat1 log level to be DEBUG",
-                        Level.DEBUG,
-                        config.getLogger("cat1").getLevel());
-            }
-        };
-        runTest(lcr, test);
+    @LoggerContextSource("classpath:log4j-comp-logger-root.xml,log4j-comp-logger-attr-override.json")
+    public void testAttributeMergeForLoggers(final LoggerContext lcr) {
+        final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+        // Test for Root log level override
+        assertEquals(Level.WARN, config.getRootLogger().getLevel(), "Expected Root logger log level to be WARN");
+
+        // Test for cat2 level override
+        final LoggerConfig cat2 = config.getLogger("cat2");
+        assertEquals(Level.INFO, cat2.getLevel(), "Expected cat2 log level to be INFO");
+
+        // Test for cat2 additivity override
+        assertTrue(cat2.isAdditive(), "Expected cat2 additivity to be true");
+
+        // Regression
+        // Check level on cat3 (not present in root config)
+        assertEquals(Level.ERROR, config.getLogger("cat3").getLevel(), "Expected cat3 log level to be ERROR");
+        // Check level on cat1 (not present in overridden config)
+        assertEquals(Level.DEBUG, config.getLogger("cat1").getLevel(), "Expected cat1 log level to be DEBUG");
     }
 
     @Test
-    public void testMissingConfig() {
-        final LoggerContextRule lcr =
-                new LoggerContextRule("classpath:log4j-comp-logger-root.xml,log4j-does-not-exist.json");
-        final Statement test = new Statement() {
-            @Override
-            public void evaluate() {
-                final AbstractConfiguration config = (AbstractConfiguration) lcr.getConfiguration();
-                assertNotNull("No configuration returned", config);
-                // Test for Root log level override
-                assertEquals(
-                        "Expected Root logger log level to be ERROR",
-                        Level.ERROR,
-                        config.getRootLogger().getLevel());
-
-                // Test for no cat2 level override
-                final LoggerConfig cat2 = config.getLogger("cat2");
-                assertEquals("Expected cat2 log level to be INFO", Level.DEBUG, cat2.getLevel());
-            }
-        };
-        runTest(lcr, test);
+    @LoggerContextSource("classpath:log4j-comp-logger-root.xml,log4j-does-not-exist.json")
+    public void testMissingConfig(final LoggerContext lcr) {
+        final AbstractConfiguration config = (AbstractConfiguration) lcr.getConfiguration();
+        assertNotNull(config, "No configuration returned");
+        // Test for Root log level override
+        assertEquals(Level.ERROR, config.getRootLogger().getLevel(), "Expected Root logger log level to be ERROR");
+
+        // Test for no cat2 level override
+        final LoggerConfig cat2 = config.getLogger("cat2");
+        assertEquals(Level.DEBUG, cat2.getLevel(), "Expected cat2 log level to be INFO");
     }
 
     @Test
-    public void testAppenderRefFilterMerge() {
-        final LoggerContextRule lcr =
-                new LoggerContextRule("classpath:log4j-comp-logger-ref.xml,log4j-comp-logger-ref.json");
-        final Statement test = new Statement() {
-            @Override
-            public void evaluate() {
-                final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-
-                final List<AppenderRef> appenderRefList =
-                        config.getLogger("cat1").getAppenderRefs();
-                final AppenderRef appenderRef = getAppenderRef(appenderRefList, "STDOUT");
-                assertTrue(
-                        "Expected cat1 STDOUT appenderRef to have a regex filter",
-                        appenderRef.getFilter() != null && appenderRef.getFilter() instanceof RegexFilter);
-            }
-        };
-        runTest(lcr, test);
+    @LoggerContextSource("classpath:log4j-comp-logger-ref.xml,log4j-comp-logger-ref.json")
+    public void testAppenderRefFilterMerge(final LoggerContext lcr) {
+        final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+
+        final List<AppenderRef> appenderRefList = config.getLogger("cat1").getAppenderRefs();
+        final AppenderRef appenderRef = getAppenderRef(appenderRefList, "STDOUT");
+        assertTrue(
+                appenderRef.getFilter() != null && appenderRef.getFilter() instanceof RegexFilter,
+                "Expected cat1 STDOUT appenderRef to have a regex filter");
     }
 
     private AppenderRef getAppenderRef(final List<AppenderRef> appenderRefList, final String refName) {
@@ -289,17 +229,4 @@ public class CompositeConfigurationTest {
         runTest(rule, test);
 
     } */
-
-    private void runTest(final LoggerContextRule rule, final Statement statement) {
-        try {
-            rule.apply(
-                            statement,
-                            Description.createTestDescription(
-                                    getClass(),
-                                    Thread.currentThread().getStackTrace()[1].getMethodName()))
-                    .evaluate();
-        } catch (final Throwable e) {
-            Throwables.rethrow(e);
-        }
-    }
 }
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromThrowableMessageTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromThrowableMessageTest.java
index d1a8d61451..8fa7450a51 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromThrowableMessageTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/NestedLoggingFromThrowableMessageTest.java
@@ -16,8 +16,8 @@
  */
 package org.apache.logging.log4j.core.impl;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -29,33 +29,28 @@ import java.util.Set;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.test.CoreLoggerContexts;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 /**
  * Test for LOG4J2-2368.
  */
+@LoggerContextSource("log4j-nested-logging-throwable-message.xml")
 public class NestedLoggingFromThrowableMessageTest {
 
     private static final File file1 = new File("target/NestedLoggerTest1.log");
     private static final File file2 = new File("target/NestedLoggerTest2.log");
 
-    @BeforeClass
-    public static void beforeClass() {
-        file1.delete();
-        file2.delete();
+    @BeforeAll
+    public static void beforeAll() {
         System.setProperty("log4j2.enableThreadlocals", "true");
     }
 
-    @Rule
-    public LoggerContextRule context = new LoggerContextRule("log4j-nested-logging-throwable-message.xml");
-
     private Logger logger;
 
-    @Before
+    @BeforeEach
     public void before() {
         logger = LogManager.getLogger(NestedLoggingFromThrowableMessageTest.class);
     }
@@ -79,7 +74,7 @@ public class NestedLoggingFromThrowableMessageTest {
         final Set<String> lines1 = readUniqueLines(file1);
         final Set<String> lines2 = readUniqueLines(file2);
 
-        assertEquals("Expected the same data from both appenders", lines1, lines2);
+        assertEquals(lines1, lines2, "Expected the same data from both appenders");
         assertEquals(2, lines1.size());
         assertTrue(lines1.contains("INFO NestedLoggingFromThrowableMessageTest Logging in getMessage "));
         assertTrue(lines1.contains("ERROR NestedLoggingFromThrowableMessageTest Test message"));
@@ -91,7 +86,7 @@ public class NestedLoggingFromThrowableMessageTest {
                 new BufferedReader(new InputStreamReader(Files.newInputStream(input.toPath())))) {
             String line;
             while ((line = reader.readLine()) != null) {
-                assertTrue("Read duplicate line: " + line, lines.add(line));
+                assertTrue(lines.add(line), "Read duplicate line: " + line);
             }
         }
         return lines;
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java
index 5f809beb22..7b46b8b561 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.logging.log4j.core.impl;
 
-import static java.util.Arrays.asList;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -28,33 +27,26 @@ import static org.hamcrest.Matchers.hasKey;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
 
-import java.util.Collection;
 import java.util.concurrent.ExecutionException;
+import java.util.stream.Stream;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.ContextDataInjector;
 import org.apache.logging.log4j.spi.ThreadContextMap;
 import org.apache.logging.log4j.util.ProviderUtil;
 import org.apache.logging.log4j.util.SortedArrayStringMap;
 import org.apache.logging.log4j.util.StringMap;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
 public class ThreadContextDataInjectorTest {
-    @Parameters(name = "{0}")
-    public static Collection<String[]> threadContextMapClassNames() {
-        return asList(new String[][] {
-            {"org.apache.logging.log4j.core.context.internal.GarbageFreeSortedArrayThreadContextMap"},
-            {"org.apache.logging.log4j.spi.DefaultThreadContextMap"}
-        });
+
+    public static Stream<String> threadContextMapClassNames() {
+        return Stream.of(
+                "org.apache.logging.log4j.core.context.internal.GarbageFreeSortedArrayThreadContextMap",
+                "org.apache.logging.log4j.spi.DefaultThreadContextMap");
     }
 
-    @Parameter
     public String threadContextMapClassName;
 
     private static void resetThreadContextMap() {
@@ -63,12 +55,7 @@ public class ThreadContextDataInjectorTest {
         ThreadContext.init();
     }
 
-    @Before
-    public void before() {
-        System.setProperty("log4j2.threadContextMap", threadContextMapClassName);
-    }
-
-    @After
+    @AfterEach
     public void after() {
         ThreadContext.remove("foo");
         ThreadContext.remove("baz");
@@ -119,14 +106,20 @@ public class ThreadContextDataInjectorTest {
         ThreadContext.put("foo", "bar");
     }
 
-    @Test
-    public void testThreadContextImmutability() {
+    @ParameterizedTest
+    @MethodSource("threadContextMapClassNames")
+    public void testThreadContextImmutability(final String name) {
+        System.setProperty("log4j2.threadContextMap", name);
+        this.threadContextMapClassName = name;
         prepareThreadContext(false);
         testContextDataInjector();
     }
 
-    @Test
-    public void testInheritableThreadContextImmutability() throws Throwable {
+    @ParameterizedTest
+    @MethodSource("threadContextMapClassNames")
+    public void testInheritableThreadContextImmutability(final String name) throws Throwable {
+        System.setProperty("log4j2.threadContextMap", name);
+        this.threadContextMapClassName = name;
         prepareThreadContext(true);
         try {
             newSingleThreadExecutor().submit(this::testContextDataInjector).get();
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java
index 8224b7473f..f10cc3e0cb 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java
@@ -29,29 +29,27 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.junit.AfterClass;
-import org.junit.ClassRule;
-import org.junit.Test;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
 
 /**
  * Test for LOG4J2-1769.
  *
  * @since 2.8
  */
+@LoggerContextSource("log4j2-json-layout.xml")
 public class ConcurrentLoggingWithJsonLayoutTest {
-    @ClassRule
-    public static LoggerContextRule context = new LoggerContextRule("log4j2-json-layout.xml");
-
     private static final String PATH = "target/test-json-layout.log";
 
-    @AfterClass
+    @AfterAll
     public static void after() {
         new File(PATH).delete();
     }
 
     @Test
-    public void testConcurrentLogging() throws Throwable {
+    public void testConcurrentLogging(final LoggerContext context) throws Throwable {
         final Logger log = context.getLogger(ConcurrentLoggingWithJsonLayoutTest.class);
         final Set<Thread> threads = Collections.synchronizedSet(new HashSet<Thread>());
         final List<Throwable> thrown = Collections.synchronizedList(new ArrayList<Throwable>());
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java
index fadd4a0fec..913ff3cc26 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java
@@ -16,7 +16,9 @@
  */
 package org.apache.logging.log4j.core.layout;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.nio.charset.StandardCharsets;
 import java.util.List;
@@ -29,33 +31,28 @@ import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.test.BasicConfigurationFactory;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.categories.Layouts;
-import org.apache.logging.log4j.test.junit.ThreadContextRule;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
+import org.apache.logging.log4j.test.junit.UsingAnyThreadContext;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
 
 /**
  * Tests {@link AbstractCsvLayout}.
  *
  * @since 2.4
  */
-@Category(Layouts.Csv.class)
+@Tag("Layouts.Csv")
+@UsingAnyThreadContext
 public class CsvLogEventLayoutTest {
     static ConfigurationFactory cf = new BasicConfigurationFactory();
 
-    @Rule
-    public final ThreadContextRule threadContextRule = new ThreadContextRule();
-
-    @AfterClass
+    @AfterAll
     public static void cleanupClass() {
         ConfigurationFactory.removeConfigurationFactory(cf);
     }
 
-    @BeforeClass
+    @BeforeAll
     public static void setupClass() {
         ConfigurationFactory.setConfigurationFactory(cf);
         final LoggerContext ctx = LoggerContext.getContext();
@@ -123,28 +120,28 @@ public class CsvLogEventLayoutTest {
         final String event0 = list.get(0 + headerOffset);
         final String event1 = list.get(1 + headerOffset);
         final char del = format.getDelimiter();
-        Assert.assertTrue(event0, event0.contains(del + "DEBUG" + del));
+        assertTrue(event0.contains(del + "DEBUG" + del), event0);
         final String quote = del == ',' ? "\"" : "";
-        Assert.assertTrue(event0, event0.contains(del + quote + "one=1, two=2, three=3" + quote + del));
-        Assert.assertTrue(event1, event1.contains(del + "INFO" + del));
+        assertTrue(event0.contains(del + quote + "one=1, two=2, three=3" + quote + del), event0);
+        assertTrue(event1.contains(del + "INFO" + del), event1);
 
         if (hasHeaderSerializer && header == null) {
-            Assert.fail();
+            fail();
         }
         if (!hasHeaderSerializer && header != null) {
-            Assert.fail();
+            fail();
         }
         if (hasFooterSerializer && footer == null) {
-            Assert.fail();
+            fail();
         }
         if (!hasFooterSerializer && footer != null) {
-            Assert.fail();
+            fail();
         }
         if (hasHeaderSerializer) {
-            Assert.assertEquals(list.toString(), header, list.get(0));
+            assertEquals(header, list.get(0), list.toString());
         }
         if (hasFooterSerializer) {
-            Assert.assertEquals(list.toString(), footer, list.get(list.size() - 1));
+            assertEquals(footer, list.get(list.size() - 1), list.toString());
         }
     }
 
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java
index 466e5ba4b1..4d061d5038 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java
@@ -16,11 +16,10 @@
  */
 package org.apache.logging.log4j.core.layout;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
@@ -31,51 +30,27 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.categories.Layouts;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
 import org.apache.logging.log4j.message.ObjectArrayMessage;
 import org.apache.logging.log4j.message.SimpleMessage;
-import org.apache.logging.log4j.test.junit.ThreadContextRule;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.apache.logging.log4j.test.junit.UsingThreadContextStack;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
 
 /**
  * Tests {@link AbstractCsvLayout}.
  *
  * @since 2.4
  */
-@RunWith(Parameterized.class)
-@Category(Layouts.Csv.class)
+@Tag("Layouts.Csv")
+@UsingThreadContextStack
+@LoggerContextSource(reconfigure = ReconfigurationPolicy.AFTER_EACH)
 public class CsvParameterLayoutTest {
-    @Parameterized.Parameters(name = "{0}")
-    public static Collection<Object[]> data() {
-        return Arrays.asList(new Object[][] {
... 1008 lines suppressed ...