Christophe Willemsen
Christophe Willemsen

Reputation: 20175

Parameterized testcontainer image tag with Junit5

In the Testcontainers documentation, there is an example for having the docker image to be parameterized with @ParameterizedTest.

This was a junit4 example.

https://github.com/testcontainers/testcontainers-java/blob/main/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java

@RunWith(Parameterized.class)
public class ParameterizedDockerfileContainerTest {

    private final String expectedVersion;

    @Rule
    public GenericContainer container;

    public ParameterizedDockerfileContainerTest(String baseImage, String expectedVersion) {
        container =
            new GenericContainer(
                new ImageFromDockerfile()
                    .withDockerfileFromBuilder(builder -> {
                        builder
                            .from(baseImage)
                            // Could potentially customise the image here, e.g. adding files, running
                            //  commands, etc.
                            .build();
                    })
            )
                .withCommand("top");
        this.expectedVersion = expectedVersion;
    }

    @Parameterized.Parameters(name = "{0}")
    public static Object[][] data() {
        return new Object[][] { //
            { "alpine:3.12", "3.12" },
            { "alpine:3.13", "3.13" },
            { "alpine:3.14", "3.14" },
            { "alpine:3.15", "3.15" },
            { "alpine:3.16", "3.16" },
        };
    }

    @Test
    public void simpleTest() throws Exception {
        final String release = container.execInContainer("cat", "/etc/alpine-release").getStdout();

        assertThat(release).as("/etc/alpine-release starts with " + expectedVersion).startsWith(expectedVersion);
    }
}

I couldn't find a way to do something similar with junit5, basically :

Ofc, with a lot of if/else, playing with beforeEach, TestInfo, ... is possible but I feel like something is wrong and I'm sure the following question has probably should be answered with junit5

How to use parameterized tests for testing with multiple database versions

Upvotes: 1

Views: 778

Answers (2)

Doug Hoard
Doug Hoard

Reputation: 21

Devopology Test Engine (Junit5 based) supports parameterized class testing. (I'm the author)

https://github.com/devopology/test-engine

Your example...

package test.neo4j;

import org.devopology.test.engine.api.AfterAll;
import org.devopology.test.engine.api.BeforeAll;
import org.devopology.test.engine.api.Parameter;
import org.devopology.test.engine.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.containers.wait.strategy.Wait;

import java.util.ArrayList;
import java.util.Collection;

public class Neo4jTest {

    @Parameter
    public String dockerImageName;

    @Parameter.Supplier
    public static Collection<String> dockerImageNames() {
        Collection<String> dockerImageNames = new ArrayList<>();
        dockerImageNames.add("neo4j:4.4.14-enterprise");
        dockerImageNames.add("neo4j:5.2.0-enterprise");
        return dockerImageNames;
    }

    private Neo4jContainer<?> neo4jContainer;

    @BeforeAll
    public void beforeAll() {
        neo4jContainer = new Neo4jContainer<>(dockerImageName)
                .waitingFor(Wait.forLogMessage(".*Started..*", 1))
                .withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes")
                .withEnv(heapSizeSetting(dockerImageName), "256M")
                .withLogConsumer(outputFrame -> System.out.print(outputFrame.getUtf8String()))
                .withoutAuthentication();

        neo4jContainer.start();
    }

    @Test
    public void test1() {
        System.out.println("test1 : dockerImageName = [" + dockerImageName + "]");

        // do something here
    }

    @Test
    public void test2() {
        System.out.println("test2 : dockerImageName = [" + dockerImageName + "]");

        // do something here
    }

    @AfterAll
    public void afterAll() {
        if (neo4jContainer != null) {
            try {
                neo4jContainer.close();
            } catch (Throwable t) {
                // DO NOTHING
            }

            neo4jContainer = null;
        }
    }

    protected static String heapSizeSetting(String dockerImageName) {
        return dockerImageName.contains("4.4")
                ? "NEO4J_dbms_memory_heap_max__size" : "NEO4J_server_memory_heap_max__size";
    }
}

Upvotes: 0

Christophe Willemsen
Christophe Willemsen

Reputation: 20175

So, it seems the equivalent to junit5 is not possible, related to this opened issue https://github.com/junit-team/junit5/issues/878#issuecomment-546459081 as mentioned by Eddù above

With the great help of Michael Simons, I could manage to do something that works

Base class :

@Testcontainers(disabledWithoutDocker = true)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public abstract class MultipleNeo4jVersionsTest {

    protected static String HEAP_SIZE = "256M";

    public static Stream<String> neo4jVersions() {
        return Stream.of("4.4.14", "5.2.0");
    }

    protected static String heapSizeSetting(Neo4jVersion version) {
        return version.equals(Neo4jVersion.V4_4)
                ? "NEO4J_dbms_memory_heap_max__size"
                : "NEO4J_server_memory_heap_max__size"
                ;
    }

    protected Neo4jContainer<?> getNeo4j(String version) {
        var imageName = String.format("neo4j:%s-enterprise", version);
        Neo4jVersion neo4jVersion = Neo4jVersion.of(version);
        Neo4jContainer<?> container = new Neo4jContainer<>(imageName)
                .withoutAuthentication()
                .withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes")
                .withEnv(heapSizeSetting(neo4jVersion), HEAP_SIZE)
                .withReuse(true);
        container.start();

        return container;
    }
}

And the actual test class

@ParameterizedTest
    @MethodSource("neo4jVersions")
    void loading_config(String version) throws Exception {
        Neo4jContainer<?> neo4j = getNeo4j(version);
        // do something here

    }

Couple of useful links

Upvotes: 5

Related Questions