/* * Copyright 2015-2023 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which * accompanies this distribution and is available at * * https://www.eclipse.org/legal/epl-v20.html */ package example; // tag::user_guide[] import static example.util.StringUtils.isPalindrome; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.DynamicContainer.dynamicContainer; import static org.junit.jupiter.api.DynamicTest.dynamicTest; import static org.junit.jupiter.api.Named.named; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; import example.util.Calculator; import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Named; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.function.ThrowingConsumer; // end::user_guide[] // @formatter:off // tag::user_guide[] class DynamicTestsDemo { private final Calculator calculator = new Calculator(); // end::user_guide[] @Tag("exclude") // tag::user_guide[] // This will result in a JUnitException! @TestFactory List dynamicTestsWithInvalidReturnType() { return Arrays.asList("Hello"); } @TestFactory Collection dynamicTestsFromCollection() { return Arrays.asList( dynamicTest("1st dynamic test", () -> assertTrue(isPalindrome("madam"))), dynamicTest("2nd dynamic test", () -> assertEquals(4, calculator.multiply(2, 2))) ); } @TestFactory Iterable dynamicTestsFromIterable() { return Arrays.asList( dynamicTest("3rd dynamic test", () -> assertTrue(isPalindrome("madam"))), dynamicTest("4th dynamic test", () -> assertEquals(4, calculator.multiply(2, 2))) ); } @TestFactory Iterator dynamicTestsFromIterator() { return Arrays.asList( dynamicTest("5th dynamic test", () -> assertTrue(isPalindrome("madam"))), dynamicTest("6th dynamic test", () -> assertEquals(4, calculator.multiply(2, 2))) ).iterator(); } @TestFactory DynamicTest[] dynamicTestsFromArray() { return new DynamicTest[] { dynamicTest("7th dynamic test", () -> assertTrue(isPalindrome("madam"))), dynamicTest("8th dynamic test", () -> assertEquals(4, calculator.multiply(2, 2))) }; } @TestFactory Stream dynamicTestsFromStream() { return Stream.of("racecar", "radar", "mom", "dad") .map(text -> dynamicTest(text, () -> assertTrue(isPalindrome(text)))); } @TestFactory Stream 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))); } @TestFactory Stream generateRandomNumberOfTestsFromIterator() { // Generates random positive integers between 0 and 100 until // a number evenly divisible by 7 is encountered. Iterator inputGenerator = new Iterator() { Random random = new Random(); // end::user_guide[] { // Use fixed seed to always produce the same number of tests for execution on the CI server random = new Random(23); } // tag::user_guide[] int current; @Override public boolean hasNext() { current = random.nextInt(100); return current % 7 != 0; } @Override public Integer next() { return current; } }; // Generates display names like: input:5, input:37, input:85, etc. Function displayNameGenerator = (input) -> "input:" + input; // Executes tests based on the current input value. ThrowingConsumer testExecutor = (input) -> assertTrue(input % 7 != 0); // Returns a stream of dynamic tests. return DynamicTest.stream(inputGenerator, displayNameGenerator, testExecutor); } @TestFactory Stream dynamicTestsFromStreamFactoryMethod() { // Stream of palindromes to check Stream inputStream = Stream.of("racecar", "radar", "mom", "dad"); // Generates display names like: racecar is a palindrome Function displayNameGenerator = text -> text + " is a palindrome"; // Executes tests based on the current input value. ThrowingConsumer testExecutor = text -> assertTrue(isPalindrome(text)); // Returns a stream of dynamic tests. return DynamicTest.stream(inputStream, displayNameGenerator, testExecutor); } @TestFactory Stream dynamicTestsFromStreamFactoryMethodWithNames() { // Stream of palindromes to check Stream> inputStream = Stream.of( named("racecar is a palindrome", "racecar"), named("radar is also a palindrome", "radar"), named("mom also seems to be a palindrome", "mom"), named("dad is yet another palindrome", "dad") ); // Returns a stream of dynamic tests. return DynamicTest.stream(inputStream, text -> assertTrue(isPalindrome(text))); } @TestFactory Stream dynamicTestsWithContainers() { return Stream.of("A", "B", "C") .map(input -> dynamicContainer("Container " + input, Stream.of( dynamicTest("not null", () -> assertNotNull(input)), dynamicContainer("properties", Stream.of( dynamicTest("length > 0", () -> assertTrue(input.length() > 0)), dynamicTest("not empty", () -> assertFalse(input.isEmpty())) )) ))); } @TestFactory DynamicNode dynamicNodeSingleTest() { return dynamicTest("'pop' is a palindrome", () -> assertTrue(isPalindrome("pop"))); } @TestFactory DynamicNode dynamicNodeSingleContainer() { return dynamicContainer("palindromes", Stream.of("racecar", "radar", "mom", "dad") .map(text -> dynamicTest(text, () -> assertTrue(isPalindrome(text))) )); } } // end::user_guide[]