JUnit 5 - Providing setUp and tearDown for an entire Test Suite
Asked Answered
C

1

9

My requirement is to have some initialization done for a set of tests and clear it off once all the tests are complete. These tests spin over a few test classes as they are not closely related, but require a common initialization.

I am using @SelectClasses to form the suite and trying to make use of @ExtendWith using a custom extension that should handle the pre and post processing. This does not work and I am unsure if an appropriate solution exists in JUnit. Sharing the sample code of what was already attempted.

Suite:

@SelectClasses({FirstTest.class, SecondTest.class})
@ExtendWith(SuiteExtension.class)
@RunWith(JUnitPlatform.class)
@SuiteDisplayName("test suite")
public class SuiteClass {
}

Extension:

public class SuiteExtension implements BeforeAllCallback, AfterAllCallback {

    @Override
    public void afterAll(ExtensionContext context) throws Exception {
        System.out.println("afterAll");
    }

    @Override
    public void beforeAll(ExtensionContext context) throws Exception {
        System.out.println("beforeAll");
    }
}

Test Class 1:

public class FirstTest {

    @Test
    void test1(){
        System.out.println("test1");
    }
}

Test Class 2:

public class SecondTest {

    @Test
    void test2(){
        System.out.println("test2");
    }
}

Output:

test1
test2

Expected Output:

beforeAll
test1
test2
afterAll
Crossbar answered 28/5, 2018 at 5:33 Comment(1)
something similar - #43283298Crossbar
S
7

Combining @RunWith (from JUnit 4) and @ExtendWith (from JUnit Jupiter) is not supported: those are extension mechanisms from two different frameworks.

Technically speaking, your SuiteClass is a JUnit 4 test class. Thus JUnit Jupiter will not register or execute any extensions for it.

With regard to suites in JUnit 5, we (the JUnit Team) have plans to provide first-class support for suites that do not require a JUnit 4 Runner (i.e., @RunWith(JUnitPlatform.class)). See all GitHub issues labeled with "suites" for details. Feel free to watch and/or comment on any of those issues.

In the interim, I believe the closest one could come to implementing "before and after suite" support in JUnit Jupiter would be to implement a custom extension that implements BeforeAllCallback and AfterAllCallback. That extension would need to track whether it has already been invoked by storing a flag in the root ExtensionContext Store (as a BeforeAllCallback), so that it only executes once before the "suite". Similarly, it would need to count the number of classes it is executed for and track that in the root Store. This would serve as a Stack or CountDownLatch. As an AfterAllCallback, the extension would need to decrement the global counter and only execute once all test classes have completed.

You'd obviously need to ensure that your suite extension is registered for each test class that belongs to the suite. Perhaps a custom composed annotation would simplify matters for you there.

Now, admittedly, I just implemented that in my head but have not yet actually coded such a "suite" extension. So if you actually implement it, I'd be interested in hearing about your experience and possibly seeing your code. ;-)

Cheers,

Sam (core committer for JUnit 5)

Slew answered 28/5, 2018 at 11:12 Comment(3)
Thanks for the inputs Sam. I will try the mentioned and share the solution I come up with.Crossbar
Just implemented this solution, where I start up a WireMock server before all integration tests. Would be so much easier if there would be a BeforeTestSuiteCallback and AfterTestSuiteCallbackSeibold
FWIW I implemented this with Spring and it worked nicely, details in https://mcmap.net/q/175376/-junit-5-inject-spring-components-to-extension-beforeallcallback-afterallcallback. Thanks for your helpful answer!Arrowhead

© 2022 - 2024 — McMap. All rights reserved.