JUnit 5 - The Next Generation of JUnit - Ted's Tool Time
-
Upload
ted-vinke -
Category
Technology
-
view
270 -
download
1
Transcript of JUnit 5 - The Next Generation of JUnit - Ted's Tool Time
Ted’s Tool TimeTed VinkeFirst8
JUnit 5 - Next Gen JUnit
May 2016
Writing Tests
Dependencies
● Group ID: org.junit
● Version: 5.0.0-SNAPSHOT
● Artifact IDs:
○ junit-commons
○ junit-console
○ junit-engine-api
○ junit-gradle
○ junit-launcher
○ junit4-engine
○ junit4-runner
○ junit5-api
○ junit5-engine
○ surefire-junit5
import static org.junit.gen5.api.Assertions.assertEquals;
import org.junit.gen5.api.Test;
class FirstJUnit5Tests {
@Test void myFirstTest() { assertEquals(2, 1 + 1); }
} No need to be public anymore - package ok, private not
The API to write tests is in junit-api
Own Junit 5 @Test annotation - with no timeout, expected, etc
No deps on JUnit 4 - new namespace
org.junit.gen5
class Lifecycle {
@BeforeAllstatic void initializeExternalResources() {
System.out.println("Initializing external resources...");
}
@BeforeEachvoid initializeMockObjects() {
System.out.println("Initializing mock objects...");
}
@Testvoid someTest() {
System.out.println("Running some test...");assertTrue(true);
}
@Testvoid otherTest() {
...
Lifecycle (1)
Basics are very similar to JUnit 4.
Source: http://blog.codefx.org/libraries/junit-5-basics/
As with JUnit4 - new instance created for every test method
@Testvoid otherTest() {
assumeTrue(true);System.out.println("Running another test...");assertNotEquals(1, 42, "Why wouldn't these be the
same?");}
@Test@Disabledvoid disabledTest() {
System.exit(1);}
@AfterEachvoid tearDown() {
System.out.println("Tearing down...");}
@AfterAllstatic void freeExternalResources() {
System.out.println("Freeing external resources...");
} }
Lifecycle (2)
Basics are very similar to JUnit 4.
Prefer @Disabled(“for reason X”)
JUnit 5 comes with many of the assertion methods that JUnit 4 has and adds a few that lend themselves well to being used with Java 8 lambdas.
All JUnit 5 assertions are static methods in the org.junit.gen5.Assertions class.
import static org.junit.gen5.api.Assertions.*;
import org.junit.gen5.api.Test;
class AssertionsDemo {
@Test void standardAssertions() { assertEquals(2, 2); assertEquals(4, 4, "The optional assertion message is now the last parameter."); assertTrue(2 == 2, () -> "Assertion messages can be lazily evaluated -- " + "to avoid constructing complex messages unnecessarily."); }}
Assertions
JUnit 5 comes with many of the assertion methods that JUnit 4 has and adds a few that lend themselves well to being used with Java 8 lambdas.
All JUnit 5 assertions are static methods in the org.junit.gen5.Assertions class.
import static org.junit.gen5.api.Assertions.*;
import org.junit.gen5.api.Test;
class AssertionsDemo {
@Test void standardAssertions() { assertEquals(2, 2); assertEquals(4, 4, "The optional assertion message is now the last parameter."); assertTrue(2 == 2, () -> "Assertion messages can be lazily evaluated -- " + "to avoid constructing complex messages unnecessarily."); }}
Assertions import static org.junit.gen5.api.Assertions.*;
import org.junit.gen5.api.Test;
class AssertionsDemo {
@Test void groupedAssertions() { assertAll("address", () -> assertEquals("John", address.getFirstName()), () -> assertEquals("User", address.getLastName()) ); }
}
In a grouped assertion all assertions are executed, and and
failures will be reported together.
org.opentest4j.MultipleFailuresError: address (2 failures)expected: <John> but was: <Ted>expected: <User> but was: <Vinke>
Hey, what’s this “opentest4j”? That’s
the Open Test Alliance for the JVM
JUnit 5 comes with many of the assertion methods that JUnit 4 has and adds a few that lend themselves well to being used with Java 8 lambdas.
All JUnit 5 assertions are static methods in the org.junit.gen5.Assertions class.
import static org.junit.gen5.api.Assertions.*;
import org.junit.gen5.api.Test;
class AssertionsDemo {
@Test void standardAssertions() { assertEquals(2, 2); assertEquals(4, 4, "The optional assertion message is now the last parameter."); assertTrue(2 == 2, () -> "Assertion messages can be lazily evaluated -- " + "to avoid constructing complex messages unnecessarily."); }}
Assertions import static org.junit.gen5.api.Assertions.*;
import org.junit.gen5.api.Test;
class AssertionsDemo {
@Test void groupedAssertions() { // In a grouped assertion all assertions are executed, and any // failures will be reported together. assertAll("address", () -> assertEquals("John", address.getFirstName()), () -> assertEquals("User", address.getLastName()) ); }
}
import static org.junit.gen5.api.Assertions.*;
import org.junit.gen5.api.Test;
class AssertionsDemo {
@Test void exceptionTesting() { Throwable exception = expectThrows(IllegalArgumentException.class, () -> { throw new IllegalArgumentException("a message"); }); assertEquals("a message", exception.getMessage()); }
}
expectedThrows replaces expected and ExpectedException
import static org.junit.gen5.api.Assertions.assertEquals;import static org.junit.gen5.api.Assumptions.*;import org.junit.gen5.api.Test;
public class AssumptionsDemo {
@Test void testOnlyOnCiServer() { assumeTrue("CI".equals(System.getenv("ENV"))); // remainder of test }
@Test void testInAllEnvironments() { assumingThat("CI".equals(System.getenv("ENV")), () -> { assertEquals(2, 2); });
// perform these assertions in all environments assertEquals("a string", "a string");
Assumptions
JUnit 5 comes with a subset of the assumption methods that JUnit 4 provides and adds a few that lend themselves well to being used with Java 8 lambdas.
import org.junit.gen5.api.*;
@Tag("fast")@Tag("model")class TaggingDemo {
@Test @Tag("taxes") void testingTaxCalculation() { }
}
Tagging and filtering
Tags can be used to filter test discovery and execution.
@DisplayName("A stack")class TestingAStack { @Test @DisplayName("is instantiated with new Stack()") void isInstantiatedWithNew() { /*...*/ } @Nested @DisplayName("when new") class WhenNew { @Test @DisplayName("is empty") void isEmpty() { /*...*/ }
Nesting Tests
@Nested @DisplayName("after pushing an element") class AfterPushing { @Test @DisplayName("it is no longer empty") void isEmpty() { /*...*/ } @Test @DisplayName("returns the element when poppe...") void returnElementWhenPopped() { /*...*/ } @Test @DisplayName( "returns the element when peeked but ...") void returnElementWhenPeeked(){ /*...*/ } } }
@DisplayName for readable classes and methods
Source: http://blog.codefx.org/libraries/junit-5-basics/
public static class HasTempFolder {@Rulepublic TemporaryFolder folder= new TemporaryFolder();
@Testpublic void testUsingTempFolder() throws IOException {
File createdFile= folder.newFile("myfile.txt");File createdFolder=
folder.newFolder("subfolder");// ...
}}
Source: http://blog.codefx.org/design/architecture/junit-5-extension-model/
How it was done in JUnit 4.
How it is done in JUnit 5.
● Test Instance Post Processing
● BeforeAll Callback
● Conditional Test Execution
● BeforeEach Callback
● Parameter Resolution
● Exception Handling
● AfterEach Callback
● AfterAll Callback
@ExtendWith(MockitoExtension.class)class MockTests { // ...}
Extensions API
Extensions can be registered declaratively via @ExtendWith. @ExtendWith({ FooExtension.class, BarExtension.class })
class MyTestsV1 { // ...}
public class BenchmarkExtension implementsBeforeAllExtensionPoint,
BeforeEachExtensionPoint,AfterEachExtensionPoint,
AfterAllExtensionPoint {
private static final Namespace NAMESPACE =
Namespace.of("BenchmarkExtension");
@Overridepublic void beforeAll(ContainerExtensionContext context) {
if (!shouldBeBenchmarked(context))return;
writeCurrentTime(context,
LaunchTimeKey.CLASS);}
@Overridepublic void beforeEach(TestExtensionContext context) {
if (!shouldBeBenchmarked(context))
Example: BenchmarkExtension
Source: http://blog.codefx.org/design/architecture/junit-5-extension-model/
@Overridepublic void afterEach(TestExtensionContext context) {
if (!shouldBeBenchmarked(context))return;
long launchTime = loadLaunchTime(context,
LaunchTimeKey.TEST);long runtime = currentTimeMillis() - launchTime;print("Test", context.getDisplayName(), runtime);
}
private static boolean shouldBeBenchmarked(ExtensionContext context) {
return context.getElement().isAnnotationPresent(Benchmark.class);
}
private static void writeCurrentTime(ExtensionContext context,
LaunchTimeKey key) {context.getStore(NAMESPACE).put(key,
currentTimeMillis());}
Interfaces
Pass context
Store information
References
●JUnit 5http://junit.org/junit5/http://junit.org/junit5/docs/current/user-guide/
●Open Test Alliance for the JVMhttps://github.com/ota4j-team/opentest4j
●Articleshttp://www.codeaffine.com/2016/02/18/junit-5-first-look/http://blog.codefx.org/libraries/junit-5-setup/
Thank you