MicroShed Testing

microshed-testing

Sharing containers

Typically a suite of tests are comprised of multiple test classes to better organize different test scenarios. Consider the following test classes:

@MicroShedTest
public class MyTestA {
    @Container
    public static ApplicationContainer app = new ApplicationContainer()
                    .withAppContextRoot("/myservice");
    // ...
}

@MicroShedTest
public class MyTestB {
    @Container
    public static ApplicationContainer app = new ApplicationContainer()
                    .withAppContextRoot("/myservice");
    // ...
}

Since each test class has its own @Container annotated field, a new container will be started for each class. Having a fresh start of a container on each test class may be intended behavior, but in many cases it is not necessary and adds a significant amount of time spent starting/stopping containers before/after each test class.

The @SharedContainerConfig annotation

If multiple test classes can share the same container instances, they can offload their @Container annotated fields to a separate class that implements SharedContainerConfiguration like so:

public class AppContainerConfig implements SharedContainerConfiguration {
    @Container
    public static ApplicationContainer app = new ApplicationContainer()
                    .withAppContextRoot("/myservice");
}

@MicroShedTest
@SharedContainerConfig(AppContainerConfig.class)
public class MyTestA {
    // ...
}

@MicroShedTest
@SharedContainerConfig(AppContainerConfig.class)
public class MyTestB {
    // ...
}

By default, shared containers will be started in parallel before the first test class that uses the @SharedContainerConfig starts. The containers will be stopped automatically when all tests have completed.

Customizing the start process for SharedContainerConfiguration

By default, shared containers are stared in parallel in order to save time. However, this may not be possible in all instances. For example, containers may have strict start order dependencies. There are two primary approaches to customizing the start process.

Using Testcontainer dependsOn API

The Testcontainers API has a built-in dependency mechanism which can be used to declare dependencies among multiple containers.

    @Container
    public static GenericContainer<?> mongo = new GenericContainer<>("mongo:3.4")
                    .withNetworkAliases("testmongo");
                    
    @Container
    public static ApplicationContainer app = new ApplicationContainer()
                    .dependsOn(mongo)
                    // ...

Since the app container dependsOn the mongo container, when MicroShed Testing starts the containers, the Testcontainers library will ensure that the mongo container starts sucessfully before the app container start is initiatied.

Fully custom start process

In some cases the start procedure may need to be customized beyond simple start ordering. For these cases, the SharedContainerConfiguration.startContainers() method can be overridden. For example:

public class AppContainerConfig implements SharedContainerConfiguration {

    @Container
    public static GenericContainer<?> mongo = new GenericContainer<>("mongo:3.4")
                    // ...

    @Container
    public static ApplicationContainer app = new ApplicationContainer()
                    // ...

    @Override
    public void startContainers() {
        mongo.start();
        app.start();
    }
}