Migrating to
JUnit 5 (alpha)
JUnit 4 JUnit 5
import org.junit.Test;
public class JUnit4Test {
@Test
public void aJunit4TestCase() {
// write test here
}
}
import org.junit.gen5.api.Test;
class JUnit5Test {
@Test
void aJunit5TestCase() {
// write test here
}
}
public @interface Test {
Class<? extends Throwable>
expected() default None.class;
long timeout() default 0L;
}
JUnit 4 JUnit 5
public @interface Test {
}
public @interface Before {}
public @interface After {}
public @interface BeforeEach {}
public @interface AfterEach {}
public @interface BeforeClass {}
public @interface AfterClass {}
public @interface BeforeAll {}
public @interface AfterAll {}
public @interface Ignore {
String value() default "";
}
public @interface Disabled {
String value() default "";
}
class FunctionalAssertionsWithHamcrest {
@Test
void testProcedural() {
File file = new File("/some/property.file");
assertTrue(file.exists());
}
@Test
void testFunctional() {
File file = new File("/some/property.file");
assertTrue(file::exists);
}
@Test
void testFunctionalGrouped() {
File file = new File("/some/property.file");
assertAll(() -> file.canWrite(), () -> file.canRead());
}
}
class AssumptionsAndExceptions {
@Test
void testFullyConditional() {
File file = new File("/some/property.file");
assumeTrue(file.exists());
runSomeRoutineDependingOn(file);
}
@Test
void testPartlyConditional() {
File file = new File("/some/property.file");
assumingThat(file.exists()), () -> {
runSomeRoutineDependingOn(file);
});
}
@Test
void testThrowsExcption() {
IOException exception = expectThrows(IOException.class, () -> {
new File("?").getCanonicalPath();
});
validate(exception);
}
}
JUnit 4 JUnit 5
public class ATest {
@Test
public void foo() {}
}
public class BTest {
@Test
public void bar() {}
}
@RunWith(Suite.class)
@Suite.SuiteClasses({
ATest.class,
BTest.class
})
public class MySuite {}
@Tag(SuiteA.class)
public class ATest {
@Test
public void foo() {}
}
@Tags(
@Tag(SuiteA.class),
@Tag(SuiteB.class)
)
public class BTest {
@Test
public void bar() {}
}
JUnit 4 JUnit 5
public class ATest {
@Test
public void foo() {}
}
public class BTest {
@Test
public void bar() {}
}
@RunWith(Suite.class)
@Suite.SuiteClasses({
ATest.class,
BTest.class
})
public class MySuite {}
@Tag(SuiteA.class)
public class ATest {
@Test
public void foo() {}
}
@Tag(SuiteA.class)
@Tag(SuiteB.class)
@Retention(RUNTIME)
public @interface Meta {}
@Meta
public class BTest {
@Test
public void bar() {}
}
@DisplayName("A stack")
class TestingAStack {
Stack<Object> stack = new Stack<Object>();
@Test @DisplayName("is empty") void isEmpty() {
Assertions.assertTrue(stack.isEmpty());
}
@Nested @DisplayName("after pushing an element")
class AfterPushing {
String anElement = "an element";
@BeforeEach void init() {
stack.push(anElement);
}
@Test @DisplayName("it is no longer empty") void isEmpty() {
Assertions.assertFalse(stack.isEmpty());
}
@Test @DisplayName("returns the element when popped")
void returnElementWhenPopped() {
Assertions.assertEquals(anElement, stack.pop());
}
}
}
class DependencyInjection {
@Test
void testSelfAware(TestInfo testInfo) {
String name = testInfo.getName();
assertTrue("selfAwareTest", name);
}
}
public interface TestInfo {
String getName();
String getDisplayName();
Set<String> getTags();
}
class DependencyInjection {
@Test
void testSelfReport(TestReporter testReporter) {
long start = System.nanoTime();
doHeavyLifting();
testReporter.publishEntry("time", System.nanoTime() - start);
}
}
public interface TestReporter {
void publishEntry(String key, String value);
void publishEntry(Map<String, String> values);
}
JUnit 4 JUnit 5
public @interface Rule {
String value() default "";
}
public @interface RunWith {
Class<? extends Runner> value();
}
public @interface ExtendWith {
Class<? extends Extension>[]
value();
}
interface ContainerExecutionCondition {...}
interface TestExecutionCondition { ... }
interface BeforeAllExtensionPoint { ... }
interface BeforeEachExtensionPoint { ... }
interface InstancePostProcessor { ... }
interface MethodParameterResolver { ... }
interface ExceptionHandlerExtensionPoint { ... }
interface AfterEachExtensionPoint { ... }
interface AfterAllExtensionPoint { ... }
@ExtendWith(FooExtension.class)
class FunctionalAssertionsWithHamcrest {
@Test
void testProcedural(@Foo File file) {
assertTrue(file.exists());
}
}
@Retention(RUNTIME)
@interface Foo {}
class FooExtension implements MethodParameterResolver {
@Override public boolean supports(Parameter parameter,
MethodInvocationContext methodInvocationContext,
ExtensionContext extensionContext) {
return parameter.isAnnotationPresent(Foo.class);
}
@Override public Object resolve(Parameter parameter,
MethodInvocationContext methodInvocationContext,
ExtensionContext extensionContext){
return new File("some/file");
}
}
Currently still unsupported:
1. Parameterized tests (no test-runner equivalent)
2. No test-timeout
3. No sorting of test methods
JInit 5 is work-in-progress and the development has slowed
down significantly. Tickets for M1 are up-for-grab on GitHub!
http://rafael.codes
@rafaelcodes
http://documents4j.com
https://github.com/documents4j/documents4j
http://bytebuddy.net
https://github.com/raphw/byte-buddy

Migrating to JUnit 5

  • 1.
  • 2.
    JUnit 4 JUnit5 import org.junit.Test; public class JUnit4Test { @Test public void aJunit4TestCase() { // write test here } } import org.junit.gen5.api.Test; class JUnit5Test { @Test void aJunit5TestCase() { // write test here } }
  • 3.
    public @interface Test{ Class<? extends Throwable> expected() default None.class; long timeout() default 0L; } JUnit 4 JUnit 5 public @interface Test { } public @interface Before {} public @interface After {} public @interface BeforeEach {} public @interface AfterEach {} public @interface BeforeClass {} public @interface AfterClass {} public @interface BeforeAll {} public @interface AfterAll {} public @interface Ignore { String value() default ""; } public @interface Disabled { String value() default ""; }
  • 4.
    class FunctionalAssertionsWithHamcrest { @Test voidtestProcedural() { File file = new File("/some/property.file"); assertTrue(file.exists()); } @Test void testFunctional() { File file = new File("/some/property.file"); assertTrue(file::exists); } @Test void testFunctionalGrouped() { File file = new File("/some/property.file"); assertAll(() -> file.canWrite(), () -> file.canRead()); } }
  • 5.
    class AssumptionsAndExceptions { @Test voidtestFullyConditional() { File file = new File("/some/property.file"); assumeTrue(file.exists()); runSomeRoutineDependingOn(file); } @Test void testPartlyConditional() { File file = new File("/some/property.file"); assumingThat(file.exists()), () -> { runSomeRoutineDependingOn(file); }); } @Test void testThrowsExcption() { IOException exception = expectThrows(IOException.class, () -> { new File("?").getCanonicalPath(); }); validate(exception); } }
  • 6.
    JUnit 4 JUnit5 public class ATest { @Test public void foo() {} } public class BTest { @Test public void bar() {} } @RunWith(Suite.class) @Suite.SuiteClasses({ ATest.class, BTest.class }) public class MySuite {} @Tag(SuiteA.class) public class ATest { @Test public void foo() {} } @Tags( @Tag(SuiteA.class), @Tag(SuiteB.class) ) public class BTest { @Test public void bar() {} }
  • 7.
    JUnit 4 JUnit5 public class ATest { @Test public void foo() {} } public class BTest { @Test public void bar() {} } @RunWith(Suite.class) @Suite.SuiteClasses({ ATest.class, BTest.class }) public class MySuite {} @Tag(SuiteA.class) public class ATest { @Test public void foo() {} } @Tag(SuiteA.class) @Tag(SuiteB.class) @Retention(RUNTIME) public @interface Meta {} @Meta public class BTest { @Test public void bar() {} }
  • 8.
    @DisplayName("A stack") class TestingAStack{ Stack<Object> stack = new Stack<Object>(); @Test @DisplayName("is empty") void isEmpty() { Assertions.assertTrue(stack.isEmpty()); } @Nested @DisplayName("after pushing an element") class AfterPushing { String anElement = "an element"; @BeforeEach void init() { stack.push(anElement); } @Test @DisplayName("it is no longer empty") void isEmpty() { Assertions.assertFalse(stack.isEmpty()); } @Test @DisplayName("returns the element when popped") void returnElementWhenPopped() { Assertions.assertEquals(anElement, stack.pop()); } } }
  • 9.
    class DependencyInjection { @Test voidtestSelfAware(TestInfo testInfo) { String name = testInfo.getName(); assertTrue("selfAwareTest", name); } } public interface TestInfo { String getName(); String getDisplayName(); Set<String> getTags(); }
  • 10.
    class DependencyInjection { @Test voidtestSelfReport(TestReporter testReporter) { long start = System.nanoTime(); doHeavyLifting(); testReporter.publishEntry("time", System.nanoTime() - start); } } public interface TestReporter { void publishEntry(String key, String value); void publishEntry(Map<String, String> values); }
  • 11.
    JUnit 4 JUnit5 public @interface Rule { String value() default ""; } public @interface RunWith { Class<? extends Runner> value(); } public @interface ExtendWith { Class<? extends Extension>[] value(); } interface ContainerExecutionCondition {...} interface TestExecutionCondition { ... } interface BeforeAllExtensionPoint { ... } interface BeforeEachExtensionPoint { ... } interface InstancePostProcessor { ... } interface MethodParameterResolver { ... } interface ExceptionHandlerExtensionPoint { ... } interface AfterEachExtensionPoint { ... } interface AfterAllExtensionPoint { ... }
  • 12.
    @ExtendWith(FooExtension.class) class FunctionalAssertionsWithHamcrest { @Test voidtestProcedural(@Foo File file) { assertTrue(file.exists()); } } @Retention(RUNTIME) @interface Foo {} class FooExtension implements MethodParameterResolver { @Override public boolean supports(Parameter parameter, MethodInvocationContext methodInvocationContext, ExtensionContext extensionContext) { return parameter.isAnnotationPresent(Foo.class); } @Override public Object resolve(Parameter parameter, MethodInvocationContext methodInvocationContext, ExtensionContext extensionContext){ return new File("some/file"); } }
  • 13.
    Currently still unsupported: 1.Parameterized tests (no test-runner equivalent) 2. No test-timeout 3. No sorting of test methods JInit 5 is work-in-progress and the development has slowed down significantly. Tickets for M1 are up-for-grab on GitHub!
  • 14.