5
EXTENSION MODEL
import org.junit.jupiter.api.extension.*;
class MyCustomExtension
implements BeforeEachCallback, AfterEachCallback {
@Override
public void beforeEach(ExtensionContext context) {
// setup
}
@Override
public void afterEach(ExtensionContext context) {
// teardown
}
}
Slide 10
Slide 10 text
5
EXTENSION REGISTRATION
Declara ve: @ExtendWith on classes or methods
Programma c: @RegisterExtension on fields
Global: via ServiceLoader
You can register as many extensions as you need
simultaneously
Slide 11
Slide 11 text
5
PROGRAMMING MODEL MEETS
EXTENSION MODEL
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.*;
import static org.junit.jupiter.api.Assertions.*;
@ExtendWith(MyCustomExtension.class)
class SimpleTest {
@RegisterExtension Extension myExtension = new AnotherExtension(42);
@Test
@ExtendWith({FooExtension.class, BarExtension.class})
void onePlusOneEqualsTwo() {
assertEquals(2, 1 + 1);
}
}
Slide 12
Slide 12 text
5
CONDITIONAL TEST
EXECUTION
Slide 13
Slide 13 text
5
DEMO
h ps:/
/github.com/marcphilipp/junit5‑extensions‑demo
Slide 14
Slide 14 text
5
EXTENSION CONTEXT
Represents the current node in the test tree, e.g. test
method or class
Provides access to meta informa on about such a node,
e.g. display name, method, class
5
LESSONS LEARNED
Using custom logic to determine whether a test
class/method should be skipped
Registering an extension globally
Deac va ng a condi on without changing the code
Slide 17
Slide 17 text
5
REUSABLE TEST
SETUP & TEARDOWN
Slide 18
Slide 18 text
5
DEMO
h ps:/
/github.com/marcphilipp/junit5‑extensions‑demo
Slide 19
Slide 19 text
5
WHY THE STORE ABSTRACTION?
An extension needs to save and retrieve data, e.g. to clean
up in the end
Extensions are instan ated once and called for mul ple
tests
Using instance variables would be error‑prone
extensionContext
.getStore(Namespace.create(...))
.getOrComputeIfAbsent("key", key -> ...)
Slide 20
Slide 20 text
5
STORE
Map ‑like interface for extensions to save and retrieve
data, e.g. store.put(key, value)
Accessed via a Namespace : Enables sharing data across
extensions, but makes it a deliberate decision (e.g.
Namespace.GLOBAL )
Reading from a Store follows the hierarchy upwards, if a
key is not found
Slide 21
Slide 21 text
5
STORE
root : ExtensionContext
displayName = "JUnit Jupiter"
parent
class1 : ExtensionContext
displayName = "TestClass1"
parent
store
test1 : ExtensionContext
displayName = "test1()"
a : Store
+ get(Object, Class): T, ...
parent
b : Store
+ get(Object, Class): T, ...
parent
c : Store
+ get(Object, Class): T, ...
Namespace
store
Namespace
store
Namespace
Slide 22
Slide 22 text
5
AUTOMATIC CLEAN‑UP
CloseableResource instances in a Store are automa cally
closed when the scope of the corresponding
ExtensionContext ends.
class DockerClientResource implements CloseableResource {
private final DockerClient dockerClient;
DockerClientResource() {
var config = DefaultDockerClientConfig.createDefaultConfigBuilder
dockerClient = DockerClientBuilder.getInstance(config).build();
}
DockerClient get() {
return dockerClient;
}
@Override public void close() throws Throwable {
dockerClient.close();
}
}
Slide 23
Slide 23 text
5
LESSONS LEARNED
Using the Store class for extension state
Using Lifecycle Callbacks to enable reuse of common
setup/teardown code
Implemen ng mul ple Extension interfaces in a single
extension
Slide 24
Slide 24 text
5
RESOLVING TEST
PARAMETERS
Slide 25
Slide 25 text
5
DEMO
h ps:/
/github.com/marcphilipp/junit5‑extensions‑demo
Slide 26
Slide 26 text
5
LESSONS LEARNED
How to resolve test method parameters in an
Extension ?
You can also inject parameters into test class constructors
and @BeforeEach / @AfterEach methods etc.
Slide 27
Slide 27 text
5
PROVIDING
ARGUMENTS FOR
PARAMETERIZED
TESTS
Slide 28
Slide 28 text
5
DEMO
h ps:/
/github.com/marcphilipp/junit5‑extensions‑demo
Slide 29
Slide 29 text
5
LESSONS LEARNED
Using Parameterized Tests
Wri ng a custom ArgumentsProvider that loads data
from a JSON file, …
Slide 30
Slide 30 text
5
FROM TESTS TO TEST
TEMPLATES
Slide 31
Slide 31 text
5
DEMO
h ps:/
/github.com/marcphilipp/junit5‑extensions‑demo
Slide 32
Slide 32 text
5
LESSONS LEARNED
Execu ng a test mul ple mes with different contexts
Implemen ng a TestInvocationContextProvider
Slide 33
Slide 33 text
5
SUPPORT CLASSES
Package org.junit.platform.commons.support contains:
AnnotationSupport to scan for custom annota ons,
including meta‑annota ons
ReflectionSupport for classpath scanning, finding
methods, invoking them etc.
5
JUNIT JUPITER IS EXTENSIBLE
A lot of extension points to choose from
The JUnit team will add more in future releases
Combining mul ple extension points in one extension is
very powerful!
Slide 37
Slide 37 text
5
THIRD‑PARTY EXTENSIONS
Spring, Mockito, Docker, Wiremock, JPA,
Selenium/WebDriver, DbUnit, Ka a, Jersey, GreenMail,
S3Mock, Citrus Framework, XWiki, …
h ps:/
/github.com/junit‑team/junit5/wiki/Third‑party‑
Extensions
Slide 38
Slide 38 text
5
GETTING STARTED
User Guide:
Sample projects for Gradle, Maven, and Ant:
Javadoc:
h p:/
/junit.org/junit5/docs/current/user‑guide/
h ps:/
/github.com/junit‑team/junit5‑samples
h p:/
/junit.org/junit5/docs/current/api/
Slide 39
Slide 39 text
5
WANTED: FEEDBACK!
StackOverflow:
Code & Issues:
Twi er:
h p:/
/stackoverflow.com/ques ons/tagged/junit5
h ps:/
/github.com/junit‑team/junit5/
h ps:/
/twi er.com/juni eam
Slide 40
Slide 40 text
5
EXAMPLE CODE
h ps:/
/github.com/marcphilipp/junit5‑extensions‑demo