Enterprise Java

JUnit5 TestSuite Alternative

JUnit4 had the TestSuiteclass to aggregate multiple tests. This is not available in JUnit 5. Generally test discovery via a bunch of named tests in a suite somewhat sucks. However, if the aim is not test-discovery, but the sharing of resources between different test classes, then it makes sense to want to create a parent.

JUnit 5 provides the @Nested annotation to allow a child class to run inside the context of its parent. The assumption is that the child class is non-static, so has access to the instance values of its parent. If we want to share test resources, we probably want to think about the class-level setup of the test suite, and somehow wiring that into the class-level setup of our child classes.

Let’s contrive a fake example that demonstrates the problem:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
@Testcontainers // use docker images
class MyTest {
    // make a DB at the start of the test in a docker container
    // takes a few minutes to boot up
    @Container
    private static final DatabaseContainer DB = createDbContainer();
 
    private static MyDao dao;
 
    @BeforeAll
    static void beforeAll() {
        dao = createDaoFrom(DB);
    }
 
    @Test
    void daoFeatureOne() {
       assertThat(dao.find("no data")).isEmpty();
    }
}

The above is a test which starts up a database in the global lifecycle of the test class. It wires up a dao object to it, and can have multiple tests that reuse that dao.

In an ideal world we could reset everything for each test, but a database is an expensive resource to start up. Maybe we can add some beforeEach and afterEach hooks to clean its data, but we wouldn’t want to bounce the database. Each time. Similarly, some framework startup cost for our dao may be undesirable if run every time.

The above, as the one and only test in our project would be fine, but what if there are other tests that also need this database… and what if it really takes AGES to run…

There’s No Suite in JUnit 5

Annoying isn’t it. If only we could do:

1
2
3
4
5
6
7
8
@JUnit5TestSuite // not real
@Children({MyDaoTest.class, MyOtherDaoTest.class})
@Testcontainers
class MyTestSuite {
    @Container
    private static final DatabaseContainer DB = createDbContainer();
 
}

That would be brilliant… but it would leave us with some questions:

  • How do we ensure the child tests don’t run outside of the suite?
  • How do these tests access the `DB` object?

A Sort of Suite Alternative

Let’s imagine that we have a static method getDb to provide the database when we need it.

Now let’s rewrite the original DaoTest to use it, and make it abstract so the test runner won’t pick it up:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
abstract class MyTestImpl implements DbProvider {
    private static MyDao dao;
 
    @BeforeAll
    static void beforeAll() {
        // access to the database container
        // from the static method (statically imported)
        dao = createDaoFrom(getDb());
    }
 
    @Test
    void daoFeatureOne() {
       assertThat(dao.find("no data")).isEmpty();
    }
}

Now we’ve got a partial test that could be run in a suite, let’s define the suite. Let’s also use @Nested to wire in the child class:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
@Testcontainers // use docker images
class MyTest {
    // make a DB at the start of the test in a docker container
    // takes a few minutes to boot up
    @Container
    private static final DatabaseContainer DB = createDbContainer();
 
    // provide the getDb function to access the container
    public static DatabaseContainer getDb() {
        return DB;
    }
 
    // test suite members are just nested classes that extend
    // the abstract class of each member of the suite
    @Nested
    class MyTest extends MyTestImpl {
    }
 
    // ... add more suite members with more @Nested
}

Disadvantages

With classes operating on each other’s static bits, this runs the risk of getting confusing.

The fact that each nested class needs to be a subclass is a bit funky too…

But this works and makes for an effective test suite.

Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: JUnit5 TestSuite Alternative

Opinions expressed by Java Code Geeks contributors are their own.

Ashley Frieze

Software developer, stand-up comedian, musician, writer, jolly big cheer-monkey, skeptical thinker, Doctor Who fan, lover of fine sounds
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ashley Frieze
4 years ago
Reply to  Josep Codinach

That is for running JUnit5 tests under JUnit4 and doesn’t provide the lifecycle/shared resources that are described in the above article.

Back to top button