Slide 1

Slide 1 text

5 JUNIT 5 EXTENSIONS 1 . 1

Slide 2

Slide 2 text

5 MARC PHILIPP Software Engineer @ LogMeIn in Karlsruhe, Germany JUnit Maintainer since 2012 Twitter: @marcphilipp Web: marcphilipp.de 1 . 2

Slide 3

Slide 3 text

5 JUNIT 5 IS RELEASED! Release date: September 10, 2017 2 . 1

Slide 4

Slide 4 text

5 J U N I T 5 P L AT F O R M Another Test P A R T Y T H I R D J U P I T E R V I N TA G E 2 . 2

Slide 5

Slide 5 text

5 JUNIT JUPITER P L AT F O R M J U P I T E R 2 . 3

Slide 6

Slide 6 text

5 JUNIT JUPITER API programming model for test authors extension model for extension authors 2 . 4

Slide 7

Slide 7 text

5 PROGRAMMING MODEL import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; class SimpleTest { @Test @DisplayName("1 + 1 = 2") @ExtendWith(MyCustomExtension.class) void onePlusOneEqualsTwo() { assertEquals(2, 1 + 1); } } 2 . 5

Slide 8

Slide 8 text

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 } } 2 . 6

Slide 9

Slide 9 text

5 EXTENSION REGISTRATION Declarative: Annotate your test classes or methods with @ExtendWith to register extensions May be used as a meta-annotation Global: Opt-in support for registration via ServiceLoader 2 . 7

Slide 10

Slide 10 text

5 CONDITIONAL TEST EXECUTION 3 . 1

Slide 11

Slide 11 text

5 DEMO 3 . 2

Slide 12

Slide 12 text

5 EXTENSION CONTEXT Represents the current node in the test tree, e.g. test method or class Provides access to meta information about such a node, e.g. display name, method, class 3 . 3

Slide 13

Slide 13 text

5 EXTENSION CONTEXT root : ExtensionContext displayName = "JUnit Jupiter" parent class1 : ExtensionContext displayName = "TestClass1" parent test1 : ExtensionContext displayName = "test1()" parent test2 : ExtensionContext displayName = "test2()" parent class2 : ExtensionContext displayName = "TestClass2" parent test3 : ExtensionContext displayName = "test3()" 3 . 4

Slide 14

Slide 14 text

5 LESSONS LEARNED How to implement custom logic to determine whether a test class/method should be skipped? How to use global extension registration? How to deactivate a condition without changing the code using system properties? 3 . 5

Slide 15

Slide 15 text

5 REUSABLE TEST SETUP & TEARDOWN 4 . 1

Slide 16

Slide 16 text

5 DEMO 4 . 2

Slide 17

Slide 17 text

5 WHY THE STORE ABSTRACTION? Methods within an extension need to save and retrieve data, e.g. to cleanup in the end Extensions are instantiated once and called for multiple tests Using instance variables would be error-prone 4 . 3

Slide 18

Slide 18 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 4 . 4

Slide 19

Slide 19 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 4 . 5

Slide 20

Slide 20 text

5 LESSONS LEARNED Using the Store class for extension state Using Lifecycle Callbacks to enable reuse of common setup/teardown code Implementing multiple Extension interfaces in a single extension 4 . 6

Slide 21

Slide 21 text

5 RESOLVING TEST PARAMETERS 5 . 1

Slide 22

Slide 22 text

5 DEMO 5 . 2

Slide 23

Slide 23 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 5 . 3

Slide 24

Slide 24 text

5 PROVIDING ARGUMENTS FOR PARAMETERIZED TESTS 6 . 1

Slide 25

Slide 25 text

5 DEMO 6 . 2

Slide 26

Slide 26 text

5 LESSONS LEARNED How to use Parameterized Tests? Writing a custom ArgumentsProvider that loads data from a JSON le, … 6 . 3

Slide 27

Slide 27 text

5 FROM TESTS TO TEST TEMPLATES 7 . 1

Slide 28

Slide 28 text

5 DEMO 7 . 2

Slide 29

Slide 29 text

5 LESSONS LEARNED How to execute a test multiple times with di erent contexts? How to implement a TestInvocationContextProvider 7 . 3

Slide 30

Slide 30 text

5 SUPPORT CLASSES Package org.junit.platform.commons.support contains: AnnotationSupport to scan for custom annotations, including meta-annotations ReflectionSupport for classpath scanning, nding methods, invoking them etc. 7 . 4

Slide 31

Slide 31 text

5 SUMMARY 8 . 1

Slide 32

Slide 32 text

5 JUNIT JUPITER IS EXTENSIBLE A lot of extension points to choose from The JUnit team will add more in future releases Combining multiple extension points in one extension is very powerful! 8 . 2

Slide 33

Slide 33 text

5 GETTING STARTED User Guide: Sample projects for Gradle and Maven: Javadoc: http://junit.org/junit5/docs/current/user-guide/ https://github.com/junit-team/junit5-samples http://junit.org/junit5/docs/current/api/ 8 . 3

Slide 34

Slide 34 text

5 WANTED: FEEDBACK! StackOver ow: Code & Issues: Twitter: http://stackover ow.com/questions/tagged/junit5 https://github.com/junit-team/junit5/ https://twitter.com/junitteam 8 . 4

Slide 35

Slide 35 text

5 THANK YOU! Example code: https://github.com/marcphilipp/junit5-extensions-demo 8 . 5