Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

JUnit 5: What's New and What's Coming - Spring I/O 2019

493 Aufrufe

Veröffentlicht am

Join core JUnit 5 committer Sam Brannen to gain insight on the latest new features in JUnit 5 as well as what’s on the horizon.

Sam will also provide tips on how to best use JUnit Jupiter to test Spring and Spring Boot apps.

Veröffentlicht in: Software
  • Als Erste(r) kommentieren

JUnit 5: What's New and What's Coming - Spring I/O 2019

  1. 1. Sam Brannen @sam_brannen JUnit
  2. 2. 2@sam_brannen #JUnit5 #springio19 Sam Brannen • Principal Software Engineer • Java Developer for over 20 years • Spring Framework Core Committer since 2007 • JUnit 5 Core Committer since October 2015
  3. 3. @sam_brannen #JUnit5 #springio19 3 Agenda JUnit 5 JUnit Jupiter Migrating from JUnit 4 New Features since 5.0 Roadmap Spring and JUnit Jupiter Q & A
  4. 4. Show of hands…
  5. 5. What is JUnit 5?
  6. 6. P L A T F O R M J U P I T E RV I N T A G E P A R T Y T H I R D
  7. 7. 7@sam_brannen #JUnit5 #springio19 JUnit 5 = Platform + Jupiter + Vintage • JUnit Platform • Foundation for launching testing frameworks on the JVM • Launcher and TestEngine APIs • ConsoleLauncher • JUnit Jupiter • New programming model & extension model for JUnit 5 • JUnit Vintage • TestEngine for running JUnit 3 & JUnit 4 based tests Revolutionary Evolutionary Necessary
  8. 8. 8@sam_brannen #JUnit5 #springio19 In a Nutshell, JUnit 5 is … • Complete rewrite of JUnit • Improving on what JUnit 4 had to offer • With extensibility in mind • Modular, Extensible, & Modern • Forward and backward compatible • JUnit Platform supports JUnit 3.8, JUnit 4, and JUnit Jupiter • Plus support for any TestEngine imaginable
  9. 9. 9@sam_brannen #JUnit5 #springio19 Third-party TestEngines • Specsy • Spek • Cucumber • Drools Scenario • jqwik source: https://github.com/junit-team/junit5/wiki/Third-party-Extensions
  10. 10. 10@sam_brannen #JUnit5 #springio19 Java Versions Baseline • AUTOMATIC-MODULE-NAM E • module-path scanning Building and testi ng against 11 and 12
  11. 11. 11@sam_brannen #JUnit5 #springio19 IDEs and Build Tools • IntelliJ: since IDEA 2016.2+ • Eclipse: since Eclipse Oxygen 4.7.1a+ • NetBeans: since Apache NetBeans 10.0 • Gradle: official test task support since Gradle 4.6 • Maven: official support since Maven Surefire 2.22.0 • Ant: junitlauncher task since Ant 1.10.3 See user guide and sample apps for examples
  12. 12. 12@sam_brannen #JUnit5 #springio19 Releases Version Date 5.0.0 September 10th, 2017 5.1.0 February 18th, 2018 5.2.0 April 29th, 2018 5.3.0 September 3rd, 2018 5.4.0 February 7th, 2019 5.4.2 April 7th, 2019
  13. 13. So, what is JUnit Jupiter?
  14. 14. 14@sam_brannen #JUnit5 #springio19 In a Nutshell, JUnit Jupiter is … “The new programming model and extension model in JUnit 5” • Programming Model • How you write tests • Annotations • Assertions • Assumptions • Types of tests • Extension Model • How you and third parties extend the framework • Spring, Mockito, Selenium, …
  15. 15. 15@sam_brannen #JUnit5 #springio19 More Powerful Programming Model What you can do with JUnit Jupiter that you can’t do with JUnit 4. • Visibility • Everything does not have to be public • Custom display names • @DisplayName: spaces, special characters, emoji 😱 • DisplayNameGenerator (since 5.4) • Tagging • @Tag replaces experimental @Category • Tag Expression Language (since 5.1)
  16. 16. 16@sam_brannen #JUnit5 #springio19 Example: CalculatorTests @DisplayName("Calculator Unit Tests") class CalculatorTests { private final Calculator calculator = new Calculator(); @Test @DisplayName("➕") void add() { assertEquals(5, calculator.add(2, 3), () -> "2 + 3 = " + (2 + 3)); } // ... }
  17. 17. 17@sam_brannen #JUnit5 #springio19 Expected Exceptions @Test @DisplayName("n ➗ 0 → ArithmeticException") void divideByZero() { Exception exception = assertThrows(ArithmeticException.class, () -> calculator.divide(1, 0)); assertEquals("/ by zero", exception.getMessage()); }
  18. 18. 18@sam_brannen #JUnit5 #springio19 Timeouts @Test @DisplayName("Ensure Fibonacci computation is 'fast enough'") void fibonacci() { // assertTimeout(ofMillis(1000), // () -> calculator.fibonacci(30)); assertTimeoutPreemptively(ofMillis(1000), () -> calculator.fibonacci(30)); }
  19. 19. DEMO basic test class
  20. 20. 20@sam_brannen #JUnit5 #springio19 Even More Power and Expressiveness • Meta-annotation support • Create your own custom composed annotations • Combine annotations from Spring and JUnit • Conditional test execution • Dependency injection for constructors and methods • Lambda expressions and method references • Interface default methods and testing traits • @Nested test classes • @RepeatedTest, @ParameterizedTest, @TestFactory • @TestInstance lifecycle management
  21. 21. Tagging & Custom Annotations
  22. 22. 22@sam_brannen #JUnit5 #springio19 Tagging @Tag("fast") @Test void myFastTest() { } • Declare @Tag on a test interface, class, or method
  23. 23. 23@sam_brannen #JUnit5 #springio19 Custom Tags @Target(METHOD) @Retention(RUNTIME) @Tag("fast") public @interface Fast { } • Declare @Tag as a meta-annotation @Fast @Test void myFastTest() {}
  24. 24. 24@sam_brannen #JUnit5 #springio19 Composed Tags @Target(METHOD) @Retention(RUNTIME) @Tag("fast") @Test public @interface FastTest { } • Declare @Tag as a meta-annotation with other annotations (JUnit, Spring, etc.) @FastTest void myFastTest() {}
  25. 25. @RepeatedTest, @ParameterizedTest, @TestFactory
  26. 26. 26@sam_brannen #JUnit5 #springio19 @RepeatedTest @RepeatedTest(5) void repeatedTest(RepetitionInfo repetitionInfo) { assertEquals(5, repetitionInfo.getTotalRepetitions()); } @RepeatedTest( value = 5, name = "Wiederholung {currentRepetition} von {totalRepetitions}" ) void repeatedTestInGerman() { // ... }
  27. 27. 27@sam_brannen #JUnit5 #springio19 Parameterized Tests (junit-jupiter-params) • Annotate a method with @ParameterizedTest instead of @Test o and specify the source of the arguments o optionally override the display name • Sources o @ValueSource: char, short, byte, int, long, float, double, String, Class o @NullSource, @EmptySource, and @NullAndEmptySource (since 5.4) o @EnumSource o @MethodSource o @CsvSource & @CsvFileSource o @ArgumentsSource & custom ArgumentsProvider
  28. 28. 28@sam_brannen #JUnit5 #springio19 Argument Conversion and Aggregation • Implicit conversion o Primitive types and their wrappers o Enums o File, URL, Currency, Locale, … o java.time types (JSR-310) o factory constructor or static factory method • Explicit conversion o @ConvertWith and custom ArgumentConverter o @JavaTimeConversionPattern built-in support for JSR-310 • Argument Aggregation (since 5.2) o Arguments and ArgumentAggregator
  29. 29. 29@sam_brannen #JUnit5 #springio19 @ParameterizedTest – @ValueSource @ParameterizedTest @ValueSource(strings = { "mom", "dad", "radar", "racecar", "able was I ere I saw elba" }) void palindromes(String candidate) { assertTrue(isPalindrome(candidate)); }
  30. 30. 30@sam_brannen #JUnit5 #springio19 @ParameterizedTest – @MethodSource @ParameterizedTest @MethodSource // ("palindromes") void palindromes(String candidate) { assertTrue(isPalindrome(candidate)); } static Stream<String> palindromes() { return Stream.of("mom", "dad", "radar", "racecar", "able was I ere I saw elba"); }
  31. 31. 31@sam_brannen #JUnit5 #springio19 Dynamic Tests @TestFactory Stream<DynamicTest> dynamicTestsFromIntStream() { // Generates tests for the first 10 even integers. return IntStream.iterate(0, n -> n + 2) .limit(10) .mapToObj(n -> dynamicTest("test" + n, () -> assertTrue(n % 2 == 0))); }
  32. 32. DEMO repeated, parameterized, and dynamic tests
  33. 33. Parallel Test Execution
  34. 34. 34@sam_brannen #JUnit5 #springio19 Configuring Parallelism (5.3) • Set junit.jupiter.execution.parallel.enabled config param to true o in junit-platform.properties o via Launcher API o as JVM system property • Configure the junit.jupiter.execution.parallel.config.strategy o dynamic (the default) o fixed o custom
  35. 35. 35@sam_brannen #JUnit5 #springio19 Execution Mode and Synchronization (5.3) • Disable parallel execution on a per test basis o @Execution(SAME_THREAD) // or CONCURRENT • Control synchronization o @ResourceLock("myResource") // default READ_WRITE o @ResourceLock(value = "myResource", mode = READ)
  36. 36. DEMO ParameterizedFibonacciTests
  37. 37. Focus on Extensibility
  38. 38. 38@sam_brannen #JUnit5 #springio19 New Extension Model • Extension • marker interface • org.junit.jupiter.api.extension • package containing all extension APIs • implement as many as you like • @ExtendWith(...) • used to register one or more extensions • interface, class, or method level o or as a meta-annotation • @RegisterExtension • programmatic registration via fields (since 5.1)
  39. 39. 39@sam_brannen #JUnit5 #springio19 Extension APIs – Lifecycle Callbacks • BeforeAllCallback • BeforeEachCallback • BeforeTestExecutionCallback • AfterTestExecutionCallback • AfterEachCallback • AfterAllCallback Extensions wrap user-supplied lifecycle methods and test methods
  40. 40. 40@sam_brannen #JUnit5 #springio19 Extension APIs – Miscellaneous • ExecutionCondition • TestInstanceFactory (since 5.3) • TestInstancePostProcessor • ParameterResolver • TestTemplateInvocationContextProvider • TestExecutionExceptionHandler • TestWatcher (since 5.4) • DisplayNameGenerator (since 5.4) • MethodOrderer (since 5.4) Dependency Injectio n Applied during the discovery phase
  41. 41. 41@sam_brannen #JUnit5 #springio19 DisplayNameGenerator (5.4) • SPI for generating custom display names for classes and methods • Configured via @DisplayNameGeneration • Implement your own • Or use a built-in implementation: • Standard: default behavior • ReplaceUnderscores: replaces underscores with spaces
  42. 42. 42@sam_brannen #JUnit5 #springio19 MethodOrderer (5.4) • API for controlling test method execution order • Configured via @TestMethodOrder • Implement your own • Or use a built-in implementation: • Alphanumeric: sorted alphanumerically • OrderAnnotation: sorted based on @Order • Random: pseudo-random ordering
  43. 43. What’s the significance of @Disabled?
  44. 44. 44@sam_brannen #JUnit5 #springio19 Conditional Test Execution • Extension Model meets Programming Model • ExecutionCondition • @Disabled • DisabledCondition • eating our own dog food ;-) • Deactivate via Launcher, JVM system property, or the junit-platform.properties file • junit.conditions.deactivate = org.junit.* Game Changer
  45. 45. 45@sam_brannen #JUnit5 #springio19 Built-in Conditions (5.1) • @Disabled (since 5.0) • @EnabledIf / @DisabledIf (may soon be deprecated) • @EnabledOnJre / @DisabledOnJre • @EnabledOnOs / @DisabledOnOs • @EnabledIfSystemProperty / @DisabledIfSystemProperty • @EnabledIfEnvironmentVariable / @DisabledIfEnvironmentVariable
  46. 46. Migrating from JUnit 4
  47. 47. 47@sam_brannen #JUnit5 #springio19 Do I have to migrate from JUnit 4 to JUnit 5? • Yes and No… • You can run JUnit 4 tests on the JUnit Platform via the VintageTestEngine • You can run JUnit 4 tests alongside JUnit Jupiter tests o In the same project • You can gradually migrate existing JUnit 4 tests to JUnit Jupiter o if you want to o or… you can just write all new tests in JUnit Jupiter
  48. 48. 48@sam_brannen #JUnit5 #springio19 Annotations, Assertions, Assumptions • @org.junit.Test  @org.junit.jupiter.api.Test • @Ignore  @Disabled • @BeforeClass / @AfterClass  @BeforeAll / @AfterAll • @Before / @After  @BeforeEach / @AfterEach • org.junit.Assert  org.junit.jupiter.api.Assertions • org.junit.Assume  org.junit.jupiter.api.Assumptions Failure message n ow comes LAST!
  49. 49. 49@sam_brannen #JUnit5 #springio19 JUnit 4 Rule Migration Support • @EnableRuleMigrationSupport o located in experimental junit-jupiter-migrationsupport module o registers 3 extensions for JUnit Jupiter • ExternalResourceSupport o TemporaryFolder, etc. • VerifierSupport o ErrorCollector, etc. • ExpectedExceptionSupport o ExpectedException
  50. 50. 50@sam_brannen #JUnit5 #springio19 JUnit 4 @Ignore and Assumption Support (5.4) • @EnableJUnit4MigrationSupport o registers the IgnoreCondition o supports @Ignore analogous to @Disabled o includes @EnableRuleMigrationSupport semantics • JUnit Jupiter supports JUnit 4 assumptions o methods in org.junit.Assume o AssumptionViolatedException
  51. 51. New since JUnit 5.0
  52. 52. 52@sam_brannen #JUnit5 #springio19 New Features since 5.0 • JUnit Maven BOM • Parallel test execution • Output capture for System.out and System.err • Tag expression language • Custom test sources for dynamic tests • Improved Kotlin support • Numerous enhancements for parameterized tests • Built-in @Enable* / @Disable* conditions • @RegisterExtension • TestInstanceFactory • …
  53. 53. 53@sam_brannen #JUnit5 #springio19 New Features since 5.4 • New junit-jupiter dependency aggregating artifact • XML report generating listener • Test Kit for testing engines and extensions • null and empty argument sources for @ParameterizedTest methods • @TempDir support for temporary directories • DisplayNameGenerator SPI • TestWatcher extension API • Ordering for @Test methods and @RegisterExtension fields • Improved JUnit 4 migration support for assumptions and @Ignore • …
  54. 54. On the Horizon…
  55. 55. 55@sam_brannen #JUnit5 #springio19 Coming in JUnit 5.5 • Boolean values in @ValueSource • Repeatable annotations for built-in conditions • Declarative, preemptive timeouts for tests in JUnit Jupiter • New InvocationInterceptor extension API • execution in a user-defined thread • Configurable test discovery implementation for test engines • …
  56. 56. 56@sam_brannen #JUnit5 #springio19 The 5.x Backlog • Custom ClassLoader • Programmatic extension management • Declarative and programmatic test suites for the JUnit Platform • Parameterized test classes • Scenario tests • New XML / JSON reporting format • …
  57. 57. Spring and JUnit Jupiter
  58. 58. 58@sam_brannen #JUnit5 #springio19 Spring Support for JUnit Jupiter • Fully integrated in Spring Framework 5.0! • Supports all Core Spring TestContext Framework features • Constructor and method injection via @Autowired, @Qualifier, @Value • Conditional test execution via SpEL expressions • ApplicationContext configuration annotations • Also works with Spring Framework 4.3 https://github.com/sbrannen/spring-test-junit5
  59. 59. 59@sam_brannen #JUnit5 #springio19 Configuring JUnit Jupiter with Spring • SpringExtension • @ExtendWith(SpringExtension.class) • @SpringJUnitConfig • @ContextConfiguration + SpringExtension • @SpringJUnitWebConfig • @SpringJUnitConfig + @WebAppConfiguration • @EnabledIf / @DisabledIf • SpEL expression evaluation for conditional execution
  60. 60. 60@sam_brannen #JUnit5 #springio19 Automatic Test Constructor Autowiring (5.2) • By default, a test class constructor must be annotated with @Autowired • The ”default” can be changed • set spring.test.constructor.autowire=true • JVM system property or SpringProperties mechanism • @TestConstructor(autowire = true/false) • Overrides default on a per-class basis
  61. 61. 61@sam_brannen #JUnit5 #springio19 Spring Boot 2.1 & JUnit Jupiter – Custom Config @Target(TYPE) @Retention(RUNTIME) // @ExtendWith(SpringExtension.class) @SpringBootTest @AutoConfigureMockMvc @Transactional public @interface SpringEventsWebTest { } • @SpringBootTest + @AutoConfigureMockMvc + @ExtendWith(SpringExtension.class)
  62. 62. 62@sam_brannen #JUnit5 #springio19 Spring Boot 2.1 & JUnit Jupiter – MockMvc Test @SpringEventsWebTest class EventsControllerTests { @Test @DisplayName("Home page should display more than 10 events") void listEvents(@Autowired MockMvc mockMvc) throws Exception { mockMvc.perform(get("/")) .andExpect(view().name("event/list")) .andExpect(model().attribute("events", hasSize(greaterThan(10)))); } } • @SpringEventsWebTest + method-level DI + MockMvc
  63. 63. 63@sam_brannen #JUnit5 #springio19 Tip: Upgrading JUnit 5 Version in Spring Boot • Popular question… • https://stackoverflow.com/a/54605523/388980 • Gradle: ext['junit-jupiter.version']='5.4.2' • Maven: <properties> <junit-jupiter.version>5.4.2</junit-jupiter.version> </properties>
  64. 64. DEMO Spring Boot 2.2 M3
  65. 65. Getting Involved
  66. 66. 66@sam_brannen #JUnit5 #springio19 How can I help out? • Participate on GitHub • Report issues • Suggest new features • Participate in discussions • Answer questions on Stack Overflow and Gitter • Support the JUnit Team with donations via Steady HQ https://steadyhq.com/en/junit
  67. 67. In closing…
  68. 68. 68@sam_brannen #JUnit5 #springio19 JUnit 5 Resources Project Homepage  http://junit.org/junit5 User Guide  http://junit.org/junit5/docs/current/user-guide Javadoc  http://junit.org/junit5/docs/current/api GitHub  https://github.com/junit-team Gitter  https://gitter.im/junit-team/junit5 Stack Overflow  http://stackoverflow.com/tags/junit5
  69. 69. 69@sam_brannen #JUnit5 #springio19 Demos Used in this Presentation https://github.com/sbrannen/junit5-demo https://github.com/junit-team/junit5/tree/master/documentation/src/test
  70. 70. Sam Brannen @sam_brannen Thanks! Q&A

×