Jens Schauder
The Next Generation
Entwickler, Freunde dürfen mich Architekt nennen
JUnit Nutzer seit 2001
JUnit 5 Supporter
Entwickler von Degraph
Internes Feld umbenennen?
NOPE!
Spring Runner? Cool!
Parameterized Runner? Cool!
Parametrisierte Spring Tests? NOPE!
Lambdas!
2012: erster Vorschlag auf Mailing Liste
2014: Diskussion bei XP-Days Hamburg
Mitte 2015: Indigo Kampagne
Ende 2015: Prototyp
Feb 2016: JUnit 5.0 Alpha
Juli 2016: JUnit Jupiter M1 & M2
Dank Degraph
Launcher starten
Launcher findet Engines
Engines finden Tests
Engines führen Tests aus
Gradle Plugin
Maven Plugin
Console Runner
IntelliJ Plugin (von JetBrains)
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
@RunWith(JUnitPlatform.class)
public class $02JUnit5WithRunnerTest {
@Test
public void someTest() {
Assertions.assertEquals(9, 3*3, "Msg last");
}
}
Workaround für Eclipse
import org.junit.jupiter.api.*;
// class needs only package scope -> reduced noise
class $04ProperJUnit5Test {
// new annotation
@Test
void someTest() { // again only package scope -> reduced noise
// Assertions replaces Assert for simple stuff
Assertions.assertEquals(5, quersumme(23));
// you probably want to use AssertJ, Hamcrest or similar anyway
}
@Test
@Disabled
// replaces @Ignored
void ignored() {
}
@Test
void abortTests() {
// abort the test -> not failed, but execution stops anyway.
Assumptions.assumeTrue(false);
}
@Test
@DisplayName("Realy Awesome Name \uD83D\uDC4C")
// should be an ok symbol -------^
void stupidName() {
}
@Test // the new @Test annotation doesn't have an 'expected'
void testExceptions() {
final String argument = "forty-two";
final IllegalArgumentException exception =
Assertions.expectThrows(IllegalArgumentException.class, () -> {
parseRomanNumeral(argument);
});
Assertions.assertTrue(exception.getMessage().contains(argument));
}
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
class $05NestedTests {
@Nested
class NestedClass {
@Test
void inNested() {}
}
@Test
void inParent() {}
// Nested does not work here
// Note that the test is in a static inner class yet not "part" of the containing test
static class NestedStaticClass {
@Test
void inStaticNested() {}
}
}
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Tags;
import org.junit.jupiter.api.Test;
@Tag("super")
@Tags({@Tag("awesome"), @Tag("cool")})
class $06TaggedTest {
@Test
void impressiveTest() {
}
@Test
@Tag("nice")
void evenBetterTest() {
}
@FastTest
void metaAnnotatedTest() {
}
}
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
@Test
public @interface FastTest {}
junitPlatform {
tags {
include 'fast', 'smoke'
// exclude 'slow', 'ci'
}
includeClassNamePattern '.*Tests'
}
@BeforeAll
static void beforeAll(){ System.out.println("before all"); }
@BeforeEach
void before(){ System.out.println("before"); }
@Test
void testOne() { System.out.println("one"); }
@Test
void testTwo() { System.out.println("two"); }
@AfterAll
static void afterAll(){ System.out.println("after all"); }
@AfterEach
void after(){ System.out.println("after"); }
before all
before
one
after
before
two
after
after all
Caffein required The following uses Java 8 features. You might want to apply caffein now. |
class $10DynamicWithCollectionTest {
private List<Integer> ints = asList(
Integer.MAX_VALUE, Integer.MIN_VALUE, -1, 0, 1, 2, 10
);
@TestFactory
List<DynamicTest> additionIsCommutative() {
List<DynamicTest> tests = new ArrayList<>();
for (Integer i : ints) {
for (Integer j : ints) {
tests.add(dynamicTest(
i + " + " + j,
() -> {
assertEquals(i + j, j + i);
}));
}
}
return tests;
}
}
class $11DynamicWithStreamsTest {
private List<Integer> ints = asList(
Integer.MAX_VALUE, Integer.MIN_VALUE, -1, 0, 1, 2, 10
);
@TestFactory
Stream<DynamicTest> additionIsCommutative() {
return ints.stream().flatMap(
i -> ints.stream().map(
j -> dynamicTest(
i + " + " + j,
() -> assertEquals(i + j, j + i)
)
)
);
}
}
class $12DynamicWithPixyDustTest extends LambdaBased {{
List<Integer> ints = asList(Integer.MAX_VALUE, Integer.MIN_VALUE, -1, 0, 1, 2, 10);
for (Integer i : ints) {
for (Integer j : ints) {
test(
format("adding integers is commutative (%d, %d)", i, j),
() -> {
assertEquals(i + j, j + i);
});
}
}
}}
public abstract class LambdaBased {
private List<DynamicTest> allTests = new ArrayList<>();
@TestFactory
List<DynamicTest> allTests(){
return allTests;
}
/** registers a test
* @param name name of the test
* @param executable the actual test
* */
protected void test(String name, Executable executable){
allTests.add(DynamicTest.dynamicTest(name, executable));
}
}
Dynamic Test Lifecycle The execution lifecycle of a dynamic test is quite different than it is for a
standard @Test case. Specifically, there are not any lifecycle callbacks for dynamic
tests. |
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith({RandomParameterResolver.class})
class $20MethodParameterResolverTest {
@Test
void testMethodParameterResolver(
String arg,
// provided by the TestInfoResolver,
// which is always present
TestInfo testInfo
) {
assertThat(testInfo.getDisplayName(), containsString("Resolver"));
assertThat(arg, startsWith("Jens"));
}
}
import org.junit.jupiter.api.extension.*;
import java.util.UUID;
public class RandomParameterResolver implements ParameterResolver {
@Override
public boolean supports(
ParameterContext parameterContext,
ExtensionContext extensionContext
) throws ParameterResolutionException {
return parameterContext.getParameter().getType() == String.class;
}
@Override
public Object resolve(
ParameterContext parameterContext,
ExtensionContext extensionContext
) throws ParameterResolutionException {
return "Jens" + UUID.randomUUID();
}
}
@ExtendWith({WithDatasource.class})
public class $21BeforeAfterExtensionTest {
@Test
public void testSomething(MyDatasource ds){
System.out.println("in test one with DS" + ds);
}
@Test
public void testSomethingElse(MyDatasource ds){
System.out.println("in test two with DS" + ds);
}
}
import org.junit.jupiter.api.extension.*;
public class WithDatasource implements
BeforeEachCallback, AfterEachCallback, ParameterResolver {
private MyDatasource ds;
@Override
public void beforeEach(TestExtensionContext testExtensionContext) {
System.out.println("before");
// more setup code goes here
ds = new MyDatasource();
}
@Override
public void afterEach(TestExtensionContext testExtensionContext) {
System.out.println("after");
ds = null;
}
@Override
public boolean supports(
ParameterContext parameterContext,
ExtensionContext extensionContext
) throws ParameterResolutionException {
return parameterContext.getParameter().getType()
.isAssignableFrom(MyDatasource.class);
}
@Override
public Object resolve(
ParameterContext parameterContext,
ExtensionContext extensionContext
) throws ParameterResolutionException {
return ds;
}
}
public class MyDatasource {
private static int counter = 0;
{counter++;}
@Override
public String toString() {
return "MyDatasource #" + counter;
}
}
before
in test one with DSMyDatasource #1
after
before
in test two with DSMyDatasource #2
after
AfterAllCallback
AfterEachCallback
AfterTestExecutionCallback
BeforeAllCallback
BeforeEachCallback
BeforeTestExecutionCallback
ContainerExecutionCondition
ParameterResolver
TestExecutionCondition
TestExecutionExceptionHandler
TestInstancePostProcessor
Tests N-Mal ausführen
Tests in anderem Thread ausführen (z.B. Swing EDT)
@API(Experimental)
Mit den Ausprägungen
Internal,
Deprecated
Experimental
Maintained
Stable
Ist in Arbeit
JUnit 5 wird wesentlich aufgeräumter
Mächtiger Extension Mechanismus
Test mit Closures möglich aber nicht 100% integriert
Schaut es euch an und gebt Feedback
Ich fürchte, die meisten werden auf die finale Version warten und dann meckern…
Kommt nach Vorne.
Ich antworte gerne.
Allen anderen einen schönen Tag.
Jens Schauder
Dieser Talk im Netz: http://schauder.github.io/junit-lambda-talk/junit.html