Common updates from JUnit 4 to JUnit 5 - neighbourhoodie/logging-log4j2 GitHub Wiki

Most of the stuff can be found here

https://www.baeldung.com/junit-5-migration

Basics

@Test(expected=...)

junit4

@Test(expected = UnsupportedOperationException.class)
public void ...() {
  convertToEntity();
}

turns to

import static org.junit.jupiter.api.Assertions.assertThrows;

@Test
public void testConvertToEntityAttribute() {
    assertThrows(UnsupportedOperationException.class, () -> this.converter.convertToEntityAttribute(null));
}

Assertions

Update the import to org.junit.jupiter.api.Assertions

Note for any assertions with error messages, the message is moved as the second argument.

For example:

// JUnit 4
assertTrue("No messages returned", messages != null && messages.size() > 0);

// JUnit 5
assertTrue(messages != null && messages.size() > 0, "No messages returned");

AssertThat

Since JUnit 5 does not directly provide assertThat, we switch to using org.hamcrest.MatcherAssert.assertThat from the hamcrest library.

Replace org.junit.Assert.assertThat with org.hamcrest.MatcherAssert.assertThat Also import the Matchers:

import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.emptyCollectionOf;
import static org.hamcrest.Matchers.hasItemInArray;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.theInstance;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.empty;

Category

Remove @Category because JUnit 5 doesn't support categories like JUnit 4. Instead, it uses tags (@Tag), which you can adapt based on your requirements.

junit4

import org.junit.experimental.categories.Category;

@Category(Layouts.Yaml.class)
public class Test {...}

junit5

import org.junit.jupiter.api.Tag;

@Tag("Layouts.Yaml")`
public class Test {...}

RunWith

MockitoJUnitRunner

Add imports:

import org.mockito.junit.jupiter.MockitoExtension;

import org.junit.jupiter.api.extension.ExtendWith;

Replace @RunWith(MockitoJUnitRunner.class) with @ExtendWith(MockitoExtension.class)

Parameterized

  • Replace @RunWith(Parameterized.class) with @ParameterizedTest. Also remove @Test as @ParameterizedTest will cover that.
  • Instead of @Parameterized.Parameters, use @MethodSource to supply the test parameters
  • Remove the constructor, as JUnit 5 passes parameters directly to the test methods
  • The data() method now returns a Stream<>, which JUnit 5 uses for parameterized tests

junit4

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import com.google.common.collect.ImmutableList;
import java.util.List;

@RunWith(Parameterized.class)
@Parameterized.Parameters(name = "{0}")
public static List<String> data() throws IOException {
    return ImmutableList.of("logger-config/LoggerConfig/", "logger-config/AsyncLoggerConfig/");
}

@Test
...

junit5

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;

public static Stream<String> data() {
    return Stream.of("logger-config/LoggerConfig/", "logger-config/AsyncLoggerConfig/");
}

@ParameterizedTest(name = "{0}")
@MethodSource("data")

Rules

ClassRule

@ClassRule is deprecated in Junit5 and, unfortunately, the translation is not straight forward. It depends on the implementation.

LoggerContextRule

junit4

import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
...
private static final String CONFIG = "log4j2-pattern-layout-with-context.xml";

@ClassRule
public static LoggerContextRule context = new LoggerContextRule(CONFIG);

public void testfun() {
  listAppender = context.getRequiredAppender("list", ListAppender.class);
  listAppender.clear();

junit5

import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
import org.apache.logging.log4j.core.test.junit.Named;

@LoggerContextSource(value = "log4j2-jdbc-dbcp2.xml")

public void beforeEach(@Named("list") final ListAppender appender) {
    this.listAppender = appender.clear();
})

If you need the context in a function, you can just pass it as a param:

public void testNoUserSet(final LoggerContext context) {
    final Logger logger = context.getLogger(getClass());

Rule

@Rule and @ClassRule no longer exist; superseded by @ExtendWith and @RegisterExtension.

Turn into an Extention

Some of the Rules can be turned into an Extention. James helped with that for the SecurityManagerTestRule and here is the example: https://github.com/neighbourhoodie/logging-log4j2/pull/9/commits/0519c80936ef780c3bce1357565c6774888d4323 or in this PR

JUnit4 Rule:
package org.apache.logging.log4j.test.junit;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class SecurityManagerTestRule implements TestRule {

    public SecurityManagerTestRule(final SecurityManager securityManager) {
        this.securityManager = securityManager;
    }

    private SecurityManager securityManagerBefore;
    private final SecurityManager securityManager;

    @Override
    public Statement apply(final Statement base, final Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                before();
                try {
                    base.evaluate();
                } finally {
                    after();
                }
            }

            private void after() {
                System.setSecurityManager(securityManagerBefore);
            }

            private void before() {
                securityManagerBefore = System.getSecurityManager();
                System.setSecurityManager(securityManager);
            }
        };
    }
}
JUnit5 Extention:
package org.apache.logging.log4j.test.junit;

import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

public class SecurityManagerExtension implements BeforeEachCallback, AfterEachCallback {
    private SecurityManager securityManagerBefore;
    private final SecurityManager securityManager;

    public SecurityManagerExtension(final SecurityManager securityManager) {
        this.securityManager = securityManager;
    }

    public void beforeEach(ExtensionContext ctx) {
        securityManagerBefore = System.getSecurityManager();
        System.setSecurityManager(securityManager);
    }

    public void afterEach(ExtensionContext ctx) {
        System.setSecurityManager(securityManagerBefore);
    }
}
File Changes for Files that used the Rule:
diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilSecurityManagerTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilSecurityManagerTest.java
index beb7cc345b..bb8365a92d 100644
--- a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilSecurityManagerTest.java
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilSecurityManagerTest.java
@@ -20,15 +20,15 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 
 import java.security.Permission;
-import org.apache.logging.log4j.test.junit.SecurityManagerTestRule;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.logging.log4j.test.junit.SecurityManagerExtension;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.ResourceLock;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 @ResourceLock("java.lang.SecurityManager")
 public class LoaderUtilSecurityManagerTest {
-    @Rule
-    public final SecurityManagerTestRule rule = new SecurityManagerTestRule(new TestSecurityManager());
+    @RegisterExtension
+    public final SecurityManagerExtension ext = new SecurityManagerExtension(new TestSecurityManager());
 
     private static class TestSecurityManager extends SecurityManager {

ThreadContextStackRule

Junit4:

public class ContextStackJsonAttributeConverterTest {
    private ContextStackJsonAttributeConverter converter;

    @Rule
    public final ThreadContextStackRule threadContextRule = new ThreadContextStackRule();

junit5

import org.apache.logging.log4j.test.junit.UsingThreadContextStack;

@UsingThreadContextStack
public class ContextStackJsonAttributeConverterTest {...}

Please update this section when they request changes for the PR we'll do in their side, to reflect the end result they are looking for.

⚠️ **GitHub.com Fallback** ⚠️