{"id":28558872,"url":"https://github.com/drandarov-io/junit-5-quick-start-guide-and-framework-support","last_synced_at":"2025-06-10T08:35:43.315Z","repository":{"id":122834785,"uuid":"63866520","full_name":"drandarov-io/JUnit-5-Quick-Start-Guide-and-Framework-Support","owner":"drandarov-io","description":"JUnit 5 Quick Start Guide and collection of examples for frameworks used in conjunction with JUnit 5","archived":false,"fork":false,"pushed_at":"2024-03-19T00:36:10.000Z","size":5823,"stargazers_count":41,"open_issues_count":4,"forks_count":10,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-09T08:14:03.424Z","etag":null,"topics":["assertion-framework","best-practices","getting","guide","java","java-8","junit","junit-5","junit5","milestones","quick","quickstart","spring-5","start","started","testing","tutorial","user","user-guide","workshop"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drandarov-io.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-07-21T12:14:59.000Z","updated_at":"2025-04-14T12:12:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"49e24bdf-95f1-436f-a79f-6ae01846a730","html_url":"https://github.com/drandarov-io/JUnit-5-Quick-Start-Guide-and-Framework-Support","commit_stats":null,"previous_names":["drandarov-io/junit-5-quick-start-guide-and-framework-support"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drandarov-io%2FJUnit-5-Quick-Start-Guide-and-Framework-Support","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drandarov-io%2FJUnit-5-Quick-Start-Guide-and-Framework-Support/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drandarov-io%2FJUnit-5-Quick-Start-Guide-and-Framework-Support/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drandarov-io%2FJUnit-5-Quick-Start-Guide-and-Framework-Support/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drandarov-io","download_url":"https://codeload.github.com/drandarov-io/JUnit-5-Quick-Start-Guide-and-Framework-Support/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drandarov-io%2FJUnit-5-Quick-Start-Guide-and-Framework-Support/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259039396,"owners_count":22796822,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assertion-framework","best-practices","getting","guide","java","java-8","junit","junit-5","junit5","milestones","quick","quickstart","spring-5","start","started","testing","tutorial","user","user-guide","workshop"],"created_at":"2025-06-10T08:35:37.185Z","updated_at":"2025-06-10T08:35:43.293Z","avatar_url":"https://github.com/drandarov-io.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Modern Testing with JUnit 5, AssertJ, Spring, TestFX and Mockito\nDmitrij Drandarov \u003chttps://github.com/dmitrij-drandarov\u003e\n:imagesdir: img\n:icons: font\n:toc:\n\n== Authors\n\n* Dmitrij Drandarov | link:https://github.com/dmitrij-drandarov[image:github.png[20px, 20px]] | link:https://twitter.com/drandarov_io[image:twitter.png[20px, 20px]] | link:https://www.xing.com/profile/Dmitrij_Drandarov[image:xing.png[20px, 20px]] | link:https://www.linkedin.com/in/dmitrij-drandarov/[image:linkedin.png[20px, 20px]]\n\n== Repository Introduction\n\nThis repository contains several modules focused on showing different frameworks and tools in conjunction with JUnit 5.\nThese are however only presented as code since the main focus of this repository is the introduction to JUnit 5.\n\n.**More practices, frameworks and tools in conjunction with JUnit 5**\n* link:00-junit-best-practice/src/test/java/com.dmitrijdrandarov/bestpractice[**Best practices**]\n* link:02-assertj/src/test/java/com.dmitrijdrandarov/assertj[**AssertJ**]\n* link:03-spring[**Spring**]\n* link:04-testfx/src/test/java/com.dmitrijdrandarov/testfx[**TestFX (ToDo)**]\n* link:05-mockito/src/test/java/com.dmitrijdrandarov/mockito[**Mockito (WIP)**]\n\n== Slides from Talk\n\nimage::05_jug_final_small.png[]\n\n* Light: link:++JUG - Modern Testing mit JUnit 5 - Light.pptx++[]\n* Dark: link:++JUG - Modern Testing mit JUnit 5.pptx++[]\n\n= JUnit 5 Quick-Start-Guide\n\n:sectnums:\n:sectlinks:\n\nTesting is important.\nWe should all know that.\nThey can help reproduce and fix problems in our code.\nThey can also remind you that you shouldn't have done something long after you forgot that you shouldn't do that thing and a lot more.\n\nThe problem is that often developers or managers see testing as some overhead for development that should be done after the code is finished if at all.\nThat's wrong: Testing should be a vital part of development!\nThat problem is something JUnit 5 can help you with.\nIt introduced a lot of interesting, fast ways to create tests.\nBe it Test-Factories, Test-Extensions (that only have to be implemented once), Lambda-Support etc.\nIt pushes the D.R.Y. principle a lot!\n\nTo follow this guide you should know the basics of testing and JUnit (4), but otherwise you wouldn't be here I guess.\n\nSome headers related to code will have a code-link behind their name directing to the corresponding class in the GitHub-Repository.\n\n== Setup\n\n.**Maven**\n[source,xml]\n----\n  \u003cdependency\u003e\n        \u003cgroupId\u003eorg.junit.jupiter\u003c/groupId\u003e\n        \u003cartifactId\u003ejunit-jupiter-api\u003c/artifactId\u003e\n        \u003cversion\u003e5.0.3\u003c/version\u003e\n        \u003cscope\u003etest\u003c/scope\u003e\n  \u003c/dependency\u003e\n----\nIf you need lagacy support for JUnit 4 or even JUnit 3 to run in parallel to JUnit 5, you can add the following dependency with the right version to your project\n[source,xml]\n----\n  \u003cdependency\u003e\n        \u003cgroupId\u003eorg.junit.vintage\u003c/groupId\u003e\n        \u003cartifactId\u003ejunit-vintage-engine\u003c/artifactId\u003e\n        \u003cversion\u003e4.12.0\u003c/version\u003e\n        \u003cscope\u003etest\u003c/scope\u003e\n  \u003c/dependency\u003e\n----\n\n.**Equivalents for Gradle**\n[source,gradle]\n----\n  testCompile 'org.junit.jupiter:junit-jupiter-api:5.0.3'\n----\n[source,gradle]\n----\n  testCompile 'org.junit.vintage:junit-vintage-engine:4.12.0'\n----\n\n\n== General changes link:01-junit-5/src/test/java/com.dmitrijdrandarov/junit5/JUnit5_01_GeneralChanges.java[(code)]\n\n\n=== Syntax\nThis paragraph contains the small or general changes made in the transition from JUnit 4 to JUnit 5.\nThose are simple but still note worthy.\n\nThe first change is made to the most basic of things: the test and the `@Test`-annotation themselves.\nYou no longer need to make the test `public`, however you still must not make it `static` or `private`.\nAlso timeout and expected parameter functionality has moved elsewhere.\n\n[source,java]\n----\n/**\n * Tests now only must not be static or private. Latter also goes for @Before.../@After...\n * timeout = ? and expected = ? functionality has now moved elsewhere. See in {@link JUnit5_01_NewFeaturesBasics}\n */\n@Test\nvoid testTest() {}\n----\n\n=== Naming\n\nOther annotations have received slight changes as well, including the common `@BeforeClass`, `@BeforeEach`, their `@After...` equivalents, `@Ignored` and the lesser known `@Category`.\nAll of these have been renamed and given the same treatment regarding `public` as `@Test`.\n\n[source,java]\n----\n/**\n * Annotation @BeforeClass was replaced by @{@link BeforeAll}. Needs to be static.\n * Same for @AfterClass.\n */\n@BeforeAll\nstatic void beforeAll() {}\n\n/**\n * Annotation @Before was replaced by @{@link BeforeEach}.\n * Same for @After.\n */\n@BeforeEach\nvoid beforeEach() {}\n\n/**\n * Annotation @Ignore was replaced by @{@link Disabled}. Sounds less negative.\n * However a reason for the deactivation will be printed which can be more advanced with features like {@link ExecutionCondition}.\n */\n@Disabled\n@Test\nvoid disabledTest() {}\n\n/**\n * JUnit 4s experimental @Category is now called {@link Tag}/{@link Tags}.\n */\n@Tag(\"abc\")\n@Test\nvoid taggedTest() {}\n----\n\n`Assert` and `Assume` classes have been renamed as well and are now called `Assertions` and `Assumptions`.\nNot much has changed for the naming of the methods of both classes.\n\n[source,java]\n----\n/**\n * Assertion Methods are now in class {@link Assertions}. Method names stayed mostly the same otherwise.\n */\n@Test\nvoid assertionsTest() {\n    Assertions.assertTrue(true); // Without static import\n    assertTrue(true);            // With static import on org.junit.jupiter.api.Assertions.assertTrue()\n}\n\n/**\n * Assumption Methods are now in class {@link Assumptions}. Method names stayed mostly the same otherwise.\n */\n@Test\nvoid assumptionsTest() {\n    Assumptions.assumeTrue(true); // Without static import\n    assumeTrue(true);             // With static import on org.junit.jupiter.api.Assumptions.assumeTrue()\n}\n----\n\n\n== New features: Basics link:01-junit-5/src/test/java/com.dmitrijdrandarov/junit5/JUnit5_02_NewFeaturesBasics.java[(code)]\n\n=== General\nHere I want to introduce some basics for the new features available in JUnit 5.\nThere is a new annotation called `@DisplayName` which is supposed to improve the readability of test reports, so you don't need 50-character test method names to make clear what the test is about at a glance.\n\n[source,java]\n----\n/**\n * Tests can now receive Display-Names via @{@link DisplayName}. These are e.g. used by the IDE, Console or the\n * {@link TestInfo}-Parameter (addressed in {@link #parameterTest(TestInfo, TestReporter)}).\n */\n@Test\n@DisplayName(\"Choose a display name\")\nvoid displayNameTest() {}\n----\n\nimage::01_displayname_result.png[]\n\nYou can now also group tests with inner classes annotated with `@Nested`.\n\n[source,java]\n----\n@Nested\n@DisplayName(\"Tests grouped by something\")\nclass groupedTests {\n\n    @Test\n    void groupedTest1() {}\n\n    @Test\n    void groupedTest2() {}\n\n}\n----\n\nimage::02_nestedTests_result.png[]\n\n=== Assertions and Lambda-Support\nNow for the probably most known and anticipated feature in JUnit 5: Lambda-Support...\nJUnit 5 `Assertions` and `Assumptions` classes and its methods now provide Lambda support.\nThis is achieved by providing methods with functional interfaces as parameters.\n\nThe most used ones are the `BooleanSupplier` and `Supplier\u003cString\u003e`.\nThe first one is used for assertions and the latter one to provide a result-message.\nThose are however just alternatives to the older plain `boolean` and `String`.\nAssertion methods like `assertTrue(...)` are now overloaded with combinations of those four parameters:\n(`boolean` | `BooleanSupplier`) \u0026 (`String` | `Supplier\u003cString\u003e`) resulting in 4 different methods.\nThis is what most lambda-supporting methods are designed like.\n\n[source,java]\n----\n/**\n * The new assertion-methods now support supplier-interfaces, meaning you can now enter lambda expressions on the\n * fly to a lot of the assert-methods.\n * E.g. by giving a {@link BooleanSupplier} for the assertion and a ({@link Supplier\u003cString\u003e} for the\n * result-message to the {@link Assertions#assertTrue(BooleanSupplier, Supplier)} method.\n */\n@Test\nvoid assertLambdaTest() {\n    assertTrue(() -\u003e Boolean.parseBoolean(\"true\")); // Simple assertTrue() with BooleanSupplier-Lambda-Implement.\n    Assertions.assertTrue(true, this.getClass()::getName); // Method references are possible as well of course\n}\n----\n\nA new important functional interface is `Executable`.\nIt is very similar to a `Runnable`, however it throws a `Throwable` meaning you can execute assertions like `assertTrue()` and an `AssertionError` may be thrown affecting your test-result.\nIt is used in several assertions like the new `assertAll(Executable... executables)` which can be also used to prevent repetition.\n\n[source,java]\n----\n/**\n * {@link Assertions} has a method called {@link Assertions#assertAll(Executable...)} that enables us to group\n * assertions, as well as reuse them.\n */\n@Test\nvoid assertAllTest() {\n    Executable[] executables = {\n            () -\u003e assertTrue(getData() \u003e= -10),\n            () -\u003e assertTrue(getData() \u003c= +15)};\n\n    Assertions.assertAll(\"Random Tests\", executables);\n    dataChanges();\n    Assertions.assertAll(\"Random Tests Again\", executables);\n}\n----\n\nThis new functional interface is also used in the new replacement of the old `@Test`-parameter `expected` which is called `assertThrows()`.\nIt asserts whether an exception was thrown.\nIf you need the exception-instance itself to e.g. assert the message, you can instead use `expectThrows()` which also has the exception as return type.\n\n[source,java]\n----\n/**\n * The expected parameter of {@link Test} has moved to {@link Assertions#assertThrows(Class, Executable)}.\n */\n@Test\nvoid assertThrowsTest() {\n    assertThrows(ArrayIndexOutOfBoundsException.class,\n            () -\u003e (new String[1])[2] = \"I will throw an Exception :)\");\n}\n----\n\n[source,java]\n----\n/**\n * You can also use {@link Assertions#assertThrows(Class, Executable)} to get the {@link Exception}-Instance if you need it.\n */\n@Test\nvoid expectThrowsTest() {\n    ArrayIndexOutOfBoundsException exc = assertThrows(ArrayIndexOutOfBoundsException.class,\n            () -\u003e (new String[1])[2] = \"I will throw an Exception :)\");\n\n    assertEquals(exc.getMessage(), \"2\");\n}\n----\n\n=== Parameter Resolver\n\nThe biggest new feature in JUnit 5 is the new Extension-API.\nA part of it is the `ParameterResolver`-Interface which is an extension of the `Extension`-Interface itself.\nThe `ParameterResolver`-Interface provide a way for dependency injection on method level by injecting data into test-method parameters.\nJUnit 5 provides two implementations by itself: `TestInfo` which contains some meta information and the appropriate Test-`Method` and Test-`Class` instances and `TestReporter` which can be used to publish test entries.\nA lot more on the Extension-Api is following further below.\n\n[source,java]\n----\n/**\n * Tests can now be provided with parameters. Those are resolved by {@link ParameterResolver}-Implementations which\n * in turn are extensions of the above mentioned {@link Extension}.\n * This enables dependency injection at method level.\n *\n * Resolvers for {@link TestInfo} and {@link TestReporter} are already provided. Other parameters require your own\n * {@link ParameterResolver}-Implementations to be added with the @{@link ExtendWith}-Annotation to either the\n * class or method.\n *\n * @param testInfo Information about the current test\n * @param testReporter Used to publish test entries\n */\n@Test\nvoid parameterTest(TestInfo testInfo, TestReporter testReporter) {\n    LOG.info(\"DisplayName:\\t\" + testInfo.getDisplayName());\n    LOG.info(\"Tags:\\t\\t\\t\" + testInfo.getTags());\n    LOG.info(\"TestClass:\\t\\t\" + testInfo.getTestClass());\n    LOG.info(\"TestMethod:\\t\\t\" + testInfo.getTestMethod());\n\n    testReporter.publishEntry(\"parameterTestTime\", String.valueOf(System.currentTimeMillis()));\n}\n----\n\n\n== New features: Advanced link:01-junit-5/src/test/java/com.dmitrijdrandarov/junit5/JUnit5_03_NewFeaturesAdvanced.java[(code)]\n\n=== Test-Parameters\nBuilding upon the `ParameterResolver` paragraph of the last chapter let's look at implementing your own `ParameterResolver`.\nYou can also see the first visual sign of the Extension-API in the form of the `@ExtendWith`-Annotation. The final result is:\n\n[source,java]\n----\n/**\n * A simple example of a {@link ParameterResolver}-Implementation. @{@link ExtendWith} is used to mark\n * {@link ClassName_ParameterResolver} and {@link ParameterIndex_ParameterResolver} as used\n * {@link ParameterResolver}. These could alternatively be placed at class level.\n *\n * @param className String-Parameter that will be injected by {@link ClassName_ParameterResolver}\n * @param parameterIndex Long-Parameter that will be injected by {@link ParameterIndex_ParameterResolver}\n */\n@Test\n@ExtendWith({ClassName_ParameterResolver.class, ParameterIndex_ParameterResolver.class})\nvoid customParameterTest(String className, Long parameterIndex) {\n    LOG.info(className);                    // Surrounding class name injected by ClassName_ParameterResolver\n    LOG.info(parameterIndex);    // Parameter-Index injected by ParameterIndex_ParameterResolver\n}\n----\n\nThis is achieved by the following implementations:\n\nThe first implementation processes the `String` parameter `className`.\nIt checks whether the parameter class is a `String` and throws an exception otherwise.\nTo resolve and inject the parameter it just returns the test classes name.\n\n[source,java]\n----\npublic class ClassName_ParameterResolver implements ParameterResolver {\n\n    /**\n     * Simple example that only checks if the Parameter-Type is a {@link String} based on the Parameter-Context to\n     * determine whether the Parameter is supported by this {@link ParameterResolver}.\n     */\n    @Override\n    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {\n        return parameterContext.getParameter().getType().equals(String.class);\n    }\n\n    /**\n     * Simple example that simply resolves the Parameter by returning the Class-Name based on the Parameter-Context.\n     */\n    @Override\n    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {\n        Class\u003c?\u003e contextClass = extensionContext.getTestClass().orElse(null);\n\n        return contextClass == null ? null : contextClass.getSimpleName();\n    }\n\n}\n----\n\nThe seconds implementation processes the `Long` parameter `parameterIndex`.\nIt does basically the same but resolves the parameter by getting the index from the `parameterContext`.\n\n[source,java]\n----\npublic class ParameterIndex_ParameterResolver implements ParameterResolver {\n\n    /**\n     * Simple example that only checks if the Parameter-Type is a {@link Long} based on the\n     * Parameter-Context to determine whether the Parameter is supported by this\n     * {@link ParameterResolver}.\n     */\n    @Override\n    public boolean supports(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {\n        return parameterContext.getParameter().getType().equals(Long.class);\n    }\n\n    /**\n     * Simple example that simply resolves the Parameter by returning the parameterIndex based\n     * on the Parameter-Context.\n     */\n    @Override\n    public Object resolve(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {\n        return (long) parameterContext.getIndex();\n    }\n\n}\n----\n\nFancier examples will be down below.\n\n=== Test-Factories\nAnother nice feature are the new Test-Factories.\nThese are annotated with `@TestFactory` instead of `@Test`.\nTheir return type is some kind of collection of ``DynamicTest``s.\nThe class `DynamicTest` provides several static methods to create those.\nYou basically have to provide test data and based on it a display name as well as some kind of `Executable`.\nIn my example you can see me using the `stream()`-method of said class.\n\n[source,java]\n----\n/**\n * An example for a {@link TestFactory} with JUnit 5.\n * {@link DynamicTest#stream(Iterator, Function, ThrowingConsumer)} provides an easy way to factorize multiple\n * tests, which will be executed automatically.\n * It's basically similar to a for-loop that reads data and asserts, but these test will be grouped and displayed\n * separately in the test results.\n *\n * @return A stream of dynamic tests\n */\n@TestFactory\nStream\u003cDynamicTest\u003e testStreamFactoryTest() {\n    Iterator\u003cString\u003e testData = Arrays.asList(new String[]{\"1\", \"2\", \"3\"}).iterator();\n\n    return DynamicTest.stream(\n            testData,                              // Input-Data for the Factory\n            s -\u003e \"Displayname: S\" + s,             // Creating DisplayNames for the test\n            Assertions::assertNotNull);            // Providing an Executable on which the test is based\n}\n----\n\nimage::03_testFactory_result.png[]\n\n=== Test-Extensions\nHere I will show you an `Extension` that is not based on the `ParameterResolver` but instead implements the `ExecutionCondition`.\nThe same thing that powers the `@Disabled` annotation.\nIf we want to customize it we need out own implementation.\nThere are about a dozen of those `Extension` categories.\n`ExecutionCondition` is just one of them.\nSome are functional interfaces like the one we're talking about, others like the `ParameterResolver` are not.\n\nMy example called `@DisabledOnMonday` does exactly what it says it does:\nIt disables that test method or class on Mondays.\nThe implementation only checks for the weekday and returns an appropriate `ConditionEvaluationResult` resulting in the test being ignored when the weekday matches.\n\n[source,java]\n----\n/**\n * An extension that disables a test class on Mondays, because nobody likes those, right?\n *\n * @author dmitrij-drandarov\n * @since 28 Jul 2016\n */\npublic class DisabledOnMonday implements ExecutionCondition {\n\n    @Override\n    public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {\n        boolean monday = Calendar.getInstance().get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY;\n\n        return monday ?\n                ConditionEvaluationResult.disabled(\"I spare you on Mondays.\") :\n                ConditionEvaluationResult.enabled(\"Don't spare you on other days though \u003e:(\");\n    }\n\n}\n----\n\nThe test method looks like this:\n\n[source,java]\n----\n/**\n * For this example I use my implementation of {@link ExecutionCondition} called {@link DisabledOnMonday} to\n * tell JUnit to disable this test on mondays, because who likes those, right?\n *\n * This annotation might just as well be placed on class level. To see how I implemented this look at\n * {@link DisabledOnMonday}.\n */\n@Test\n@ExtendWith(DisabledOnMonday.class)\nvoid disabledOnMondayTest() {}\n----\n\nAgain: This could without problem be placed on class-level.\n\n\n== Advanced Examples link:01-junit-5/src/test/java/com.dmitrijdrandarov/junit5/JUnit5_04_AdvancedExamples.java[(code)]\n\n=== Extended disabled weekdays\nLet's extend that `@DisabledOnMonday` annotation a bit.\nWhat if you want to choose the weekday?\nCreating 7 annotations is kind of overkill.\nA way to achieve this could be to add another annotation that accepts the weekdays as a parameter:\n\n[source,java]\n----\n/**\n * Here I go a step further and annotate my days dynamically, by specifying the days I don't want the test to run\n * on with another custom annotation called @{@link DisabledWeekdays}.\n *\n * My extension {@link DisabledOnWeekday} later searches for @{@link DisabledWeekdays} and determines whether the\n * test should run or not.\n */\n@Test\n@DisabledWeekdays({Calendar.THURSDAY, Calendar.SATURDAY})\n@ExtendWith(DisabledOnWeekday.class)\nvoid disabledOnWeekdaysTest() {}\n----\n\nThe `@DisabledWeekdays` annotation doesn't do much more than hold an int array corresponding to the weekdays.\n\n[source,java]\n----\n/**\n * A simple annotation to retain information about weekdays that the annotated tests are disabled on.\n * Used by {@link DisabledOnWeekday}-Extension.\n *\n * @author dmitrij-drandarov\n * @since 28 Jul 2016\n */\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface DisabledWeekdays {\n    int[] value();\n}\n----\n\nThe extension looks slightly different now, since it needs to determine the weekdays from the annotation.\nLuckily the `evaluateExecutionCondition()`-method provides the `ExtensionContext` so it's fairly easy to get those.\n\n[source,java]\n----\n/**\n * An extension that disables this test class on the weekday specified by {@link DisabledWeekdays}.\n *\n * @author dmitrij-drandarov\n * @since 28 Jul 2016\n */\npublic class DisabledOnWeekday implements ExecutionCondition {\n\n    @Override\n    public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {\n\n        // Search for the @DisabledWeekdays annotation from the TestExtensionContext\n        Optional\u003cAnnotatedElement\u003e contextElement = context.getElement();\n        AnnotatedElement annotatedElement = contextElement.orElse(null);\n\n        if (annotatedElement == null) return null;\n\n        DisabledWeekdays weekdayAnnotation = annotatedElement.getAnnotation(DisabledWeekdays.class);\n\n        // Determine whether the test should be disabled\n        boolean weekdayToday = IntStream.of(weekdayAnnotation.value())\n                .anyMatch(day -\u003e day == Calendar.getInstance().get(Calendar.DAY_OF_WEEK));\n\n        // Return a ConditionEvaluationResult based on the outcome of the boolean weekdayToday\n        return weekdayToday ?\n                ConditionEvaluationResult.disabled(\"I spare you today.\") :\n                ConditionEvaluationResult.enabled(\"Don't spare you on other days though \u003e:(\");\n    }\n\n}\n----\n\n=== Extend Test-Annotation\nSo what if you want to save some that space occupied by all those annotations.\nLet's make it all-in-one for this example:\n\n[source,java]\n----\n/**\n * Here I use an annotation @{@link UITest} that is annotated by @{@link Test} itself, so it will be executed\n * properly. @{@link UITest} contains grouped information and annotations about this test like predefined\n * extensions. Further information in @{@link UITest}s JavaDoc.\n *#\n * This of course could be also possible for the examples above.\n */\n@UITest(\"../../sample.fxml\")\nvoid userInterfaceTest(Pane root) {\n    LOG.info(root.getPrefWidth());    // 555.0 (defined in FXML-File)\n    LOG.info(root.getPrefHeight());   // 333.0 (defined in FXML-File)\n}\n----\n\nWhat you basically do here is to create a new annotation and annotate that with `@Test`.\nThen you pack all you need in there like your extensions, parameter resolvers, targets, parameters, etc.\nThe annotation `@UITest` above looks like this:\n\n[source,java]\n----\n/**\n * Test annotated by this will be executed by the test runner without problems due to @{@link Test} being included.\n * You can basically group annotations by doing this and save some space, by not having to add all those\n * {@link ExtendWith}s etc. to each method.\n * Readability inside the test classes is the key here. And it looks cooler ;)\n *\n * @author dmitrij-drandarov\n * @since 29 Jul 2016\n */\n@Test\n@Tag(\"userInterface\")                      // For simple identification by ParameterResolvers\n@ExtendWith(PrintUITestData.class)         // Prints UI Test Data before each test\n@ExtendWith(RootElementResolver.class)     // Resolves the root pane\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)        // Required for the test to be automatically executed\npublic @interface UITest {\n\n    /**\n     * FXML-Path.\n     *\n     * @return FXML-Path used for the UI-Test.\n     */\n    String value();\n\n}\n----\n\nThe extensions used do not really matter here.\nOne extension resolves the `Pane` from the fxml path and the other one just prints some data.\nThis is rather a showcase of an `@Test`-Extension and utilizing the extension features of JUnit 5.\nIf you want to see code nevertheless look into the repository.\n\n=== Benchmarking Example\n\nAs for the last example right now I will showcase some benchmarking possibilities and it isn't even that complicated.\nThere are several extensions that can be used for that.\n`BeforeAllCallback`, `BeforeTestExecutionCallback` and their `After...`-equivalents.\nEach of these interfaces has a method that will be executed at some point during the tests.\nE.g. before each test or after etc.\nSo by implementing those 4 interfaces in one extension we can create a class that timestamps each time a method is called and after it finished including calculating the difference.\nThen we just need to annotate an annotation `@Benchmarked` with that extension and then place that on top of a test-method or -class.\nDone!\nThe final benchmarked test-method will should something like this:\n\n[NOTE]\n====\nThe implementation is just for showcase. It isn't very accurate or performant.\n====\n\n[source,java]\n----\n/**\n * For this example I wrote an annotation @{@link Benchmarked} that doesn't include @{@link Test} - which it could -\n * but instead only contains an self-written extension called {@link BenchmarkExtension}. Annotating your class\n * with this will basically provide you with automatic benchmarking.\n *\n * This could of course be also placed on top of the class.\n */\n@Test\n@Benchmarked\nvoid benchmarkedTest() {\n    LOG.info(\"Calculating some primes...\");\n    int primeCount = 200000;\n\n    assertEquals(primeCount, IntStream.iterate(2, i -\u003e i + 1)\n            .filter(i -\u003e LongStream.rangeClosed(2, (long) (Math.sqrt(i))).allMatch(n -\u003e i % n != 0))\n            .limit(primeCount).toArray().length);\n}\n----\n\nThe corresponding test-output:\n\nimage::04_benchmarked_output.png[]\n\nThe extension couldn't be simpler:\n\n[source,java]\n----\n/**\n * Extension, that does the logging for the benchmarks. (Implementation is not accurate or performant!)\n *\n * @author dmitrij-drandarov\n * @since 29 Jul 2016\n */\npublic class BenchmarkExtension implements BeforeAllCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, AfterAllCallback {\n\n    private static final String APD = \"\\t-\\t\";\n\n    private static final Map\u003cString, Long\u003e startTime = new HashMap\u003c\u003e();\n    private static final DateFormat dtForm = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);\n\n    @Override\n    public void beforeAll(ExtensionContext context) throws Exception {\n        String disp = context.getDisplayName();\n        long start = currentTimeMillis();\n\n        LOG.info(\"#### Summary           \\t\" + APD + disp + \" ####\");\n        LOG.info(\"#### Start of Benchmark\\t\" + APD + disp + APD + dtForm.format(new Date(start)) + \" ####\");\n        startTime.put(disp, start);\n    }\n\n    @Override\n    public void beforeTestExecution(ExtensionContext context) throws Exception {\n        String disp = context.getDisplayName();\n        long start = currentTimeMillis();\n\n        LOG.info(\"#### Method-Benchm. ####\" + APD + disp + APD + dtForm.format(new Date(start)));\n        startTime.put(context.getDisplayName(), start);\n    }\n\n    @Override\n    public void afterTestExecution(ExtensionContext context) throws Exception {\n        String disp = context.getDisplayName();\n        long end = currentTimeMillis();\n\n        LOG.info(\"#### Summary        ####\" + APD + disp);\n        LOG.info(\"#### Start          ####\" + APD + dtForm.format(new Date(startTime.get(disp))));\n        LOG.info(\"#### End            ####\" + APD + dtForm.format(new Date(end)));\n        LOG.info(\"#### Duration       ####\" + APD + (end - startTime.get(disp)) + \" ms\\n\");\n    }\n\n    @Override\n    public void afterAll(ExtensionContext context) throws Exception {\n        String disp = context.getDisplayName();\n        long end = currentTimeMillis();\n\n        LOG.info(\"#### End of Benchmark  \\t\" + APD + disp + APD + dtForm.format(new Date(end)) + \" ####\");\n        LOG.info(\"#### Duration for class\\t\" + APD + disp + APD + (end - startTime.get(disp)) + \" ms ####\");\n    }\n\n}\n----\n\nOf course I could have also included `@Benchmarked` in a separate `@BenchmarkedTest` annotation that would have extended `@Test` as well saving that one line.\n\n\n== Closing words\n\n=== Contribution\nFeel free to express critique and contribute to the https://github.com/msg-DAVID-GmbH/JUnit-5-QuickStart-Guide-and-Advanced[repository] :)\n\n=== Usage\nYou can use this repository in any way you want.\nMay it be for workshops or presentations. Just give credits. ;)\n\n=== Further Reference\n[%hardbreaks]\n* http://junit.org/junit5/docs/current/user-guide[Official JUnit 5 User Guide]\n* https://github.com/junit-team/junit5[JUnit 5 GitHub]\n* https://github.com/junit-team/junit5/milestones/[JUnit 5 Milestone plan]\n* http://files.zeroturnaround.com/pdf/zt_junit_cheat_sheet.pdf[Cheat Sheet from ZERO TURNAROUND]\n\n== Repository Timeline\n\n* Everything else is now tracked as issues\n* [x] Update for M4-RC2                                 -   07 Sep 2017\n* [x] Fix userInterfaceTest                             -   01 Aug 2017\n* [x] Create wiki article with githup-pages-content     -   04 Mar 2017\n* [x] Convert code fragments from images to text        -   04 Mar 2017\n* [x] Incorporate JUnit Best-Practice on request        -   15 Feb 2017\n* [x] Change name                                       -   05 Aug 2016\n* [x] Finish Stream TODOs                               -   05 Aug 2016\n* [x] Proper Presentation                               -   04 Aug 2016\n* [x] Add reference                                     -   03 Aug 2016\n* [x] Add expectThrows()                                -   03 Aug 2016\n* [x] Add @Nested                                       -   03 Aug 2016\n* [x] Adjust packages and classes for presentation      -   01 Aug 2016\n* [x] Extend Test-Extensions                            -   29 Jul 2016\n* [x] Test-Extensions (o\\j\\j\\api\\extension)             -   28 Jul 2016\n* [x] @TestFactory + DynamicTests                       -   26 Jul 2016\n* [x] Reorder packages and classes                      -   26 Jul 2016\n* [x] Links to Java-Files                               -   24 Jul 2016\n* [x] Dependency Copy-Paste Resource                    -   24 Jul 2016\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrandarov-io%2Fjunit-5-quick-start-guide-and-framework-support","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrandarov-io%2Fjunit-5-quick-start-guide-and-framework-support","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrandarov-io%2Fjunit-5-quick-start-guide-and-framework-support/lists"}