Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JUnit 6 + exploring the testing ecosystem

Avatar for Jeanne Boyarsky Jeanne Boyarsky
March 05, 2026
8

JUnit 6 + exploring the testing ecosystem

We’ll start out by looking at what is new in JUnit 6. However, there’s more to testing than just JUnit so you’ll also learn how to use other libraries like Hamcrest, AssertJ, JUnit Pioneer, Selenium. You’ll also see a comparison of the most common mocking libraries. After some tips for using your IDE to help you with testing, you’ll learn about some common testing patterns.

Avatar for Jeanne Boyarsky

Jeanne Boyarsky

March 05, 2026
Tweet

Transcript

  1. https://linktr.ee/jeanneboyarsky Agenda 4 • JUnit 6 • Readable Assertions •

    AssertJ • JUnit Pioneer • Mocking • Selenium • IDE Integration • Patterns/Techniques
  2. https://linktr.ee/jeanneboyarsky At a Glance 7 JUnit 3 JUnit 4 JUnit

    5 JUnit 6 Released 2002 2006 2017 2025 Minimum Java Minimum Kotlin 1.5 n/a 5 n/a 8 1.6 17 2.1 Import (prefix) junit.frameworkorg.junit org.junit.jupiter org.junit.jupiter Annotations No @Test @Before @Test @BeforeEach @BeforeAll etc @Test @BeforeEach @BeforeAll etc Assertion message First param First param Last param Last param Parameterized test Roll your own @RunWith @Paramterized Test @Paramterized Test
  3. https://linktr.ee/jeanneboyarsky Maven 9 <dependencyManagement> <dependencies> <dependency> <groupId>org.junit</groupId> <artifactId>junit-bom</artifactId> <version>6.0.3</version> <type>pom</type>

    <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> </dependencies>
  4. https://linktr.ee/jeanneboyarsky BOM Includes 10 • junit-jupiter • junit-jupiter-api • junit-jupiter-engine

    • junit-jupiter-migrationsupport • junit-jupiter-params • junit-vintage-engine • junit-platform-commons • junit-platform-console • junit-platform-engine • junit-platform-launcher • junit-platform-reporting • junit-platform-suite • junit-platform-suite-api • junit-platform-suite-engine • junit-platform-testkit
  5. https://linktr.ee/jeanneboyarsky Deprecations 11 • JUnit 4 tests • JUnit 4

    @Ignore • All other things JUnit 4 • JRE constants from Java 8-15 • Others (likely you aren’t using them unless building a tool): https://docs.junit.org/6.0.3/api/deprecated-list.html
  6. https://linktr.ee/jeanneboyarsky Changes (cont) 12 • Unified versioning. All libraries start

    with 6.X • Faster test discovery, lower memory use • @CsvSource and @CsvFileSource faster and better error messages • ParameterizedTest display names more consistent: name = value
  7. https://linktr.ee/jeanneboyarsky Changes 13 • --fail-fast for command line (or tools)

    to stop after first failure • @Nested classes in deterministic, not obvious order • Requires failsafe/surefire 3.0.0+ • More changes for tool authors such as parallelization
  8. https://linktr.ee/jeanneboyarsky What does this output? 15 // public String getFavoriteActivity()

    { // return "swimming"; // } @Test void summerFunWithPureJUnit() { assertTrue(fun.getFavoriteActivity().startsWith("swim")); assertTrue(fun.getFavoriteActivity().startsWith("tennis")); } org.opentest4j.AssertionFailedError: Expected :true Actual :false
  9. https://linktr.ee/jeanneboyarsky Making this better (with JUnit) 16 @Test void summerFunWithReadableOutput()

    { assertTrue(fun.getFavoriteActivity().startsWith("swim"), "expected to start with 'swim' but was " + fun.getFavoriteActivity()); assertTrue(fun.getFavoriteActivity().startsWith("tennis"), "expected to start with 'tennis' but was " + fun.getFavoriteActivity()); } org.opentest4j.AssertionFailedError: expected to start with 'tennis' but was swimming ==> Expected :true Actual :false
  10. https://linktr.ee/jeanneboyarsky Making this better (with Hamcrest) 17 import static org.hamcrest.MatcherAssert.assertThat;

    import static org.hamcrest.Matchers.*; … @Test void summerFunWithHamcrest() { assertThat(fun.getFavoriteActivity(), startsWith("swim")); assertThat(fun.getFavoriteActivity(), startsWith("tennis")); } java.lang.AssertionError: Expected: a string starting with "tennis" but: was "swimming" Expected :a string starting with "tennis" Actual :"swimming"
  11. https://linktr.ee/jeanneboyarsky Making this better (with Hamcrest) 18 import static org.hamcrest.MatcherAssert.assertThat;

    import static org.hamcrest.Matchers.*; … @Test void summerFunWithHamcrest() { assertThat(fun.getFavoriteActivity(), startsWith("swim")); assertThat(fun.getFavoriteActivity(), startsWith("tennis")); } java.lang.AssertionError: Expected: a string starting with "tennis" but: was "swimming" Expected :a string starting with "tennis" Actual :"swimming"
  12. https://linktr.ee/jeanneboyarsky Making this better (with AssertJ) 19 import static org.assertj.core.api.Assertions.assertThat;

    … @Test void summerFunWithAssertJ() { assertThat(fun.getFavoriteActivity()).startsWith("swim"); assertThat(fun.getFavoriteActivity()).startsWith("tennis"); } java.lang.AssertionError: Expecting actual: "swimming" to start with: "tennis"
  13. https://linktr.ee/jeanneboyarsky Adding a custom message (AssertJ) 20 @Test void summerFunMessageWithAssertJ()

    { assertThat(fun.getFavoriteActivity()) .as("I like swimming").startsWith("swim"); assertThat(fun.getFavoriteActivity()) .as("I like tennis").startsWith("tennis"); } java.lang.AssertionError: [I like tennis] Expecting actual: "swimming" to start with: "tennis" Warning: Placement of as() matters
  14. https://linktr.ee/jeanneboyarsky Multiple checks 21 // public List<String> getFavoriteActivities() { //

    return List.of("swimming", "sunbathing"); // } @Test void summerFunListWithHamcrest() { assertThat(fun.getFavoriteActivities(), hasItem("sunbathing")); assertThat(fun.getFavoriteActivities(), hasSize(2)); } @Test void summerFunListWithAssertJ() { assertThat(fun.getFavoriteActivities()) .contains(“sunbathing") .hasSize(2); }
  15. https://linktr.ee/jeanneboyarsky Which more readable? 22 @Test void summerFunListWithHamcrest() { assertThat(fun.getFavoriteActivities(),

    hasItem("sunbathing")); assertThat(fun.getFavoriteActivities(), hasSize(2)); } @Test void summerFunAllOfHamcrest() { assertThat(fun.getFavoriteActivities(), Matchers.<Collection<String>> allOf( hasSize(2), hasItem("sunbathing") )); }
  16. https://linktr.ee/jeanneboyarsky Checking Each Element 23 @Test void summerFunStartingCharacterWithHamcrest() { assertThat(fun.getFavoriteActivities(),

    everyItem(startsWith("s"))); } @Test void summerFunStartingCharacterWithAssertJ() { assertThat(fun.getFavoriteActivities()) .allSatisfy(w -> assertThat(w).startsWith("s")); }
  17. https://linktr.ee/jeanneboyarsky Sample Assertions 24 Hamcrest AssertJ Null nullValue() notNullValue() isNull()

    isNotNull() Equality is(o) not(o) equalTo() older version isEqualTo(o) isNotEqualTo(o) String startsWith(s) endsWith(s) equalToIgnoringCase(s) startsWith(s) endsWith(s) isEqualToIgnoringCase(s) Collection hasSize(n) hasItems(x) not(hasItem(x)) hasSize(n) contains(x) doesNotContain(x)
  18. https://linktr.ee/jeanneboyarsky Comparing 25 Hamcrest • Declarative • Older • Less

    updates • Multiple or combined assertions • Integration with JUnit 4 assertThat or standalone in JUnit 5 AssertJ • Fluent • Newer • More updates • Chaining assertions (faciliates autocomplete) • Can use with JUnit 4 or 5
  19. https://linktr.ee/jeanneboyarsky Testing Exceptions 27 var actual = assertThrows(ThunderstormException.class, () ->

    fun.weatherCheck()); assertThat(actual.getMessage().contains(“pool")); assertThrows(IllegalStateException.class, () -> fun.weatherCheck()); org.opentest4j.AssertionFailedError: Unexpected exception type thrown, Expected :class java.lang.IllegalStateException Actual :class com.jeanneboyarsky.example.SummerFun$ThunderstormException
  20. https://linktr.ee/jeanneboyarsky Soft Assertions 28 @Test void callingAssertAll() { var softly

    = new SoftAssertions(); softly.assertThat(“robot") .isEqualTo("izzy"); softly.assertThat(126) .isLessThanOrEqualTo(125); softly.assertAll();; } org.assertj.core.error. AssertJMultipleFailuresError: Multiple Failures (2 failures) -- failure 1 -- expected: "izzy" but was: "robot" at SoftAssertionsTest.calling… -- failure 2 -- Expecting actual: 126 to be less than or equal to: 125 at SoftAssertionsTest.calling…
  21. https://linktr.ee/jeanneboyarsky Custom Assertion 29 class CustomAssertions extends AbstractAssert<CustomAssertions, String> {

    public CustomAssertions(String actual) { super(actual, CustomAssertions.class); } public static CustomAssertions assertThat(String actual) { return new CustomAssertions(actual); } public CustomAssertions isTennis() { if (! "tennis".equals(actual)) failWithMessage("Must be tennis but was %s", actual); return this; } }
  22. https://linktr.ee/jeanneboyarsky More AssertJ Capabilities 31 • Recursive assertions • More

    types: • date • path • file • numbers • collections - ex: extract/filter data • etc
  23. https://linktr.ee/jeanneboyarsky Disable Until 33 @Test @DisabledUntil(date="2025-10-31", reason = "Need our

    partner service to be ready") void waitingForServiceAvailability() { … } timestamp = 2025-07-05T11:50:33.673759, DisabledUntil = This test is disabled until 2025-10-31. If executing it on this commit would fail, the build can't be reproduced after that date. The `date` 2025-10-31 is after the current date 2025-07-05
  24. https://linktr.ee/jeanneboyarsky Retrying a Test 34 @RetryingTest(10) void flakeyTest() { Random

    random = new Random(); if (random.nextInt(1, 100) < 75) { fail("too high"); } }
  25. https://linktr.ee/jeanneboyarsky System Properties 35 @Test @ClearSystemProperty(key = "JAVA_HOME") void clearProperty()

    { assertNull(System.getProperty("JAVA_HOME"), "path"); } @Test @SetSystemProperty( key = "JAVA_HOME", value = "c:/java/java21") void maskProperty() { assertEquals("c:/java/java21", System.getProperty("JAVA_HOME")); } Also @SetEnvironmentVariable
  26. https://linktr.ee/jeanneboyarsky More Pioneer Capabilities 37 • System in/out/err • Set

    detault time zone/locale • Disable selected parameterized tests • Expected to fail (fails if passes) • Parameterized tests with JSON • Temporary directories (also in JUnit) • etc
  27. https://linktr.ee/jeanneboyarsky Test Doubles 39 Term Description Dummy Passed in; never

    used Fake Some working implementation; simple Stub Contrived responses Spy Merge real and mock behavior Mock Preprogrammed with expectations
  28. https://linktr.ee/jeanneboyarsky Class to test 40 public interface ScoreService { int

    retrieveScore(int matchNumber); } public class Dashboard { private ScoreService service; public Dashboard(ScoreService service) { this.service = service; } public List<Integer> getScores(int maxMatch) { return IntStream.range(1, maxMatch + 1) .mapToObj(n -> service.retrieveScore(n)) .toList(); } }
  29. https://linktr.ee/jeanneboyarsky Mockito 41 @ExtendWith(MockitoExtension.class) public class DashboardTest { private Dashboard

    dashboard; @Mock private ScoreService scoreServiceMock; @BeforeEach void setUp() { dashboard = new Dashboard(scoreServiceMock); }
  30. https://linktr.ee/jeanneboyarsky Mockito (cont) 42 @Test void getScores() { when(scoreServiceMock.retrieveScore(1)).thenReturn(76); when(scoreServiceMock.retrieveScore(2)).thenReturn(91);

    List<Integer> expected = List.of(76, 91); List<Integer> actual = dashboard.getScores(2); assertEquals(expected, actual, "scores"); verify(scoreServiceMock, times(2)).retrieveScore(anyInt()); } }
  31. https://linktr.ee/jeanneboyarsky EasyMock 43 @ExtendWith(EasyMockExtension.class) public class DashboardTest { private Dashboard

    dashboard; @Mock private ScoreService scoreServiceMock; @BeforeEach void setUp() { dashboard = new Dashboard(scoreServiceMock); }
  32. https://linktr.ee/jeanneboyarsky EasyMock (cont) 44 @Test void getScores() { expect(scoreServiceMock.retrieveScore(1)).andReturn(76); expect(scoreServiceMock.retrieveScore(2)).andReturn(91);

    replay(scoreServiceMock); List<Integer> expected = List.of(76, 91); List<Integer> actual = dashboard.getScores(2); assertEquals(expected, actual, "scores"); verify(scoreServiceMock); } }
  33. https://linktr.ee/jeanneboyarsky More Mockito Capabilities 45 • Strict or lenient modes

    • Exceptions • Stubbing • Spies (monitor real objects) • Verify args, # of times API called • Mocking final classes, static methods • etc
  34. https://linktr.ee/jeanneboyarsky Creating driver 47 WebDriver driver = null; try {

    var options = new ChromeOptions(); options.addArguments("--headless=new"); driver = new ChromeDriver(options); … } finally { if (driver != null) driver.close(); }
  35. https://linktr.ee/jeanneboyarsky Reading HTML 48 driver.get("https://www.kcdc.info"); var element = driver.findElement( By.cssSelector(“a[href$='/speakers']"));

    assertEquals(“https://www.kcdc.info/speakers", element.getAttribute("href"), “url"); assertEquals(“Speakers", element.getAttribute("textContent").strip(), "display name");
  36. https://linktr.ee/jeanneboyarsky Dynamic load/longer way 49 driver.get("https://www.kcdc.info/speakers"); var wait = new

    WebDriverWait(driver, Duration.ofSeconds(60)); wait.until(ExpectedConditions.presenceOfElementLocated( By.tagName("h3"))); boolean match = driver.findElements(By.tagName("h3")) .stream() .anyMatch(e -> "Jeanne Boyarsky".equals(e.getText())); assertTrue(match, "Found Jeanne in speaker list");
  37. https://linktr.ee/jeanneboyarsky Locator types 50 • By.id • By.name • By.className

    • By.tagName • By.cssSelector • By.xpath • By.linkText • By.partialLinkText
  38. https://linktr.ee/jeanneboyarsky More Selenium Capabilities 51 • Many browser integrations •

    Automate clicking/forms • Can capture screenshots • Selenium IDE • Selenium Grid • etc
  39. https://linktr.ee/jeanneboyarsky Generating Tests 57 Technique Available In Generating class/stub methods

    Direct in IDE Test Me Generation IntelliJ AI written tests AI plugins
  40. https://linktr.ee/jeanneboyarsky Golden Master 60 • Regression test output doesn’t change

    • Save last good value • text block • file • If changes, decide if correct • Update golden master if so
  41. https://linktr.ee/jeanneboyarsky Behavior Driven Development 61 • Given a new conference

    attendee who wants to eat lunch • When the last morning session ends • Then there will be signage to food
  42. https://linktr.ee/jeanneboyarsky Mutation Testing 62 • High code coverage isn’t enough

    • Run tests many times with mutants • If a mutant is not detected, tests insufficient