Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JUGBB2020: Testcontainers - Past, Present, Future

JUGBB2020: Testcontainers - Past, Present, Future

Sergei Egorov

February 25, 2020
Tweet

More Decks by Sergei Egorov

Other Decks in Programming

Transcript

  1. Testcontainers:

    a year-in-review
    Sergei Egorov
    @bsideup

    View Slide

  2. About me
    • Testcontainers co-maintainer

    • Staff Engineer at Pivotal’s Spring R&D, working on Project Reactor ⚛

    • Java Champion

    • Berlin Spring User Group co-organizer

    • Developer tools geek
    @bsideup

    View Slide

  3. Integration testing?

    View Slide

  4. @bsideup

    View Slide

  5. @bsideup

    View Slide

  6. https://martinfowler.com/bliki/IntegrationTest.html @bsideup

    View Slide

  7. https://martinfowler.com/bliki/IntegrationTest.html @bsideup

    View Slide

  8. https://martinfowler.com/bliki/IntegrationTest.html @bsideup

    View Slide

  9. https://labs.spotify.com/2018/01/11/testing-of-microservices/
    “Microservices Testing Honeycomb”
    @bsideup

    View Slide

  10. https://labs.spotify.com/2018/01/11/testing-of-microservices/
    “Microservices Testing Honeycomb”
    @bsideup
    We’re here

    View Slide

  11. Some signs of having Integrated Tests are:
    • We spin up other services in a local testing environment
    • We test against other services in a shared testing environment
    • Changes to your system breaks tests for other systems
    https://labs.spotify.com/2018/01/11/testing-of-microservices/ @bsideup

    View Slide

  12. Integration testing transformation
    @bsideup

    View Slide

  13. Mocking
    Integration testing transformation
    @bsideup

    View Slide

  14. Mocking
    Local DBs
    Integration testing transformation
    @bsideup

    View Slide

  15. Mocking
    Local DBs
    VMs

    (Vagrant)
    Integration testing transformation
    @bsideup

    View Slide

  16. Mocking
    Local DBs
    VMs

    (Vagrant)
    Docker
    Integration testing transformation
    @bsideup

    View Slide

  17. View Slide

  18. Abstraction layer

    View Slide

  19. CI friendly

    View Slide

  20. Cross-platform

    View Slide

  21. Mocking
    Local DBs
    VMs

    (Vagrant)
    Docker
    Integration testing transformation
    @bsideup

    View Slide

  22. Mocking
    Local DBs
    VMs

    (Vagrant)
    Docker
    Fig

    (aka Docker Compose)
    Integration testing transformation
    @bsideup

    View Slide

  23. Docker Compose FTW!
    redis:
    image: redis
    ports:
    - "6379:6379"
    postgres:
    image: postgres
    ports:
    - "5432:5432"
    elasticsearch:
    image: elasticsearch:5.0.0
    ports:
    - "9200:9200"
    @bsideup

    View Slide

  24. But…

    View Slide

  25. Declarative YAML
    redis:
    image: redis
    ports:
    - "6379:6379"
    postgres:
    image: postgres
    ports:
    - "5432:5432"
    elasticsearch:
    image: elasticsearch:5.0.0
    ports:
    - "9200:9200"
    @bsideup

    View Slide

  26. No ports randomization
    redis:
    image: redis
    ports:
    - "6379:6379"
    postgres:
    image: postgres
    ports:
    - "5432:5432"
    elasticsearch:
    image: elasticsearch:5.0.0
    ports:
    - "9200:9200"
    @bsideup

    View Slide

  27. Container per test?
    redis:
    image: redis
    ports:
    - "6379:6379"
    postgres:
    image: postgres
    ports:
    - "5432:5432"
    elasticsearch:
    image: elasticsearch:5.0.0
    ports:
    - "9200:9200"
    @bsideup

    View Slide

  28. IDE integration?
    @bsideup

    View Slide

  29. Mocking
    Local DBs
    VMs

    (Vagrant)
    Docker
    Fig

    (aka Docker Compose)
    Integration testing transformation
    @bsideup

    View Slide

  30. Mocking
    Local DBs
    VMs

    (Vagrant)
    Docker
    Fig

    (aka Docker Compose)
    Docker API
    Integration testing transformation
    @bsideup

    View Slide

  31. Fighting with Docker environment

    View Slide

  32. There is no place like

    View Slide

  33. There is no place like
    … unless there is

    View Slide

  34. Can we improve that?

    View Slide

  35. View Slide

  36. Testcontainers
    • Created by Richard North in 2015

    • github.com/testcontainers/testcontainers-java
    • Wraps docker-java library

    • Docker environment discovery (Win, Mac, Linux)

    • Containers cleanup on JVM shutdown
    @bsideup

    View Slide

  37. As simple as
    PostgreSQLContainer postgresql = new PostgreSQLContainer()
    GenericContainer redis = new GenericContainer("redis:3")
    .withExposedPorts(6379)
    @bsideup

    View Slide

  38. Users

    View Slide

  39. @bsideup

    View Slide

  40. Demo

    View Slide

  41. 1.6.x
    Jan, 2018
    @bsideup

    View Slide

  42. 1.6.x
    • Kafka module
    Jan, 2018
    @bsideup
    try (KafkaContainer kafka = new KafkaContainer()) {
    kafka.start();
    testKafkaFunctionality(kafka.getBootstrapServers());
    }

    View Slide

  43. 1.6.x
    • Kafka module

    • “Ryuk”
    Jan, 2018
    @bsideup

    View Slide

  44. 1.7.x
    Apr, 2018
    @bsideup

    View Slide

  45. 1.7.x
    • Maven BOM
    Apr, 2018
    @bsideup



    org.testcontainers
    testcontainers-bom
    1.11.2
    bom
    import



    View Slide

  46. 1.7.x
    • Maven BOM

    • DockerCompose

    wait strategies
    Apr, 2018
    @bsideup
    new DockerComposeContainer(new File("docker-compose.yml"))
    .withExposedService(
    "redis_1",
    REDIS_PORT,
    Wait.forListeningPort()
    )
    .withExposedService(
    "db_1",
    3306,
    Wait.forLogMessage(".*ready for connections.*\\s", 1)
    );

    View Slide

  47. 1.7.x
    • Maven BOM

    • DockerCompose

    wait strategies

    • Daemon threads
    Apr, 2018
    @bsideup
    kiraThread.setDaemon(true);
    kiraThread.start();

    View Slide

  48. 1.7.x
    • Maven BOM

    • DockerCompose

    wait strategies

    • Daemon threads

    • MockServer module
    Apr, 2018
    @bsideup
    try (MockServerContainer mockServer = new MockServerContainer()) {
    mockServer.start();
    String expectedBody = "Hello Default World!";
    MockServerClient client = new MockServerClient(
    mockServer.getContainerIpAddress(),
    mockServer.getServerPort()
    );
    client.when(request("/hello")).respond(response(expectedBody));
    // ...
    }

    View Slide

  49. 1.8.x
    Jun, 2018
    @bsideup

    View Slide

  50. 1.8.x
    • OkHttp transport
    Jun, 2018
    @bsideup

    View Slide

  51. 1.8.x
    • OkHttp transport

    • Test framework

    agnostic
    Jun, 2018
    @bsideup
    public interface Startable extends AutoCloseable {
    void start();
    void stop();
    }
    public interface TestLifecycleAware {
    default void beforeTest(TestDescription description) {}
    default void afterTest(
    TestDescription description,
    Optional throwable
    ) {}
    }

    View Slide

  52. 1.8.x
    • OkHttp transport

    • Test framework

    agnostic

    • Docker cred. helpers
    Jun, 2018
    @bsideup
    {
    "auths": {
    },
    "HttpHeaders": {
    "User-Agent": "Docker-Client/18.03.0-ce (darwin)"
    },
    "credHelpers": {
    "registry.example.com": “helper"
    }
    }

    View Slide

  53. 1.8.x
    • OkHttp transport

    • Test framework

    agnostic

    • Docker cred. helpers

    • copyFileToContainer
    Jun, 2018
    @bsideup
    GenericContainer container = new GenericContainer("alpine:latest")
    // Look, Ma! No volumes mounting!
    .withCopyFileToContainer(
    MountableFile.forClasspathResource(“/mappable-resource/"),
    containerPath
    )

    View Slide

  54. 1.8.x
    • OkHttp transport

    • Test framework

    agnostic

    • Docker cred. helpers

    • copyFileToContainer

    • Pulsar module
    • Couchbase module
    • Cassandra module
    Jun, 2018
    @bsideup

    View Slide

  55. 1.9.x
    Sep, 2018
    @bsideup

    View Slide

  56. 1.9.x
    • OkHttp by default
    Sep, 2018
    @bsideup

    View Slide

  57. 1.9.x
    • OkHttp by default

    • Windows npipe support
    Sep, 2018
    @bsideup
    No longer needed

    View Slide

  58. 1.9.x
    • OkHttp by default

    • Windows npipe support

    • Registry auth on Windows
    Sep, 2018
    @bsideup

    View Slide

  59. 1.9.x
    • OkHttp by default

    • Windows npipe support

    • Registry auth on Windows

    • Fix local Docker Compose

    on Windows
    Sep, 2018
    @bsideup
    new DockerComposeContainer(new File("docker-compose.yml"))
    .withExposedService("redis_1", REDIS_PORT)
    .withExposedService("db_1", 3306)
    .withLocalCompose(true);

    View Slide

  60. 1.9.x
    • OkHttp by default

    • Windows npipe support

    • Registry auth on Windows

    • Fix local Docker Compose

    on Windows

    • Host ports exposing
    Sep, 2018
    @bsideup
    @BeforeClass
    public static void setUp() {
    localPort = server.getAddress().getPort();
    Testcontainers.exposeHostPorts(localPort);
    }
    @Rule
    public BrowserWebDriverContainer browser = new BrowserWebDriverContainer()
    .withCapabilities(new ChromeOptions());
    @Test
    public void testContainerRunningAgainstExposedHostPort() {
    RemoteWebDriver webDriver = browser.getWebDriver();
    webDriver.get( String.format("http://host.testcontainers.internal:%d/", localPort));
    final String pageSource = webDriver.getPageSource();
    assertTrue(pageSource.contains("Hello from the host!"));
    }

    View Slide

  61. 1.9.x
    • OkHttp by default

    • Windows npipe support

    • Registry auth on Windows

    • Fix local Docker Compose

    on Windows

    • Host ports exposing

    • Random ports in Couchbase
    Sep, 2018
    @bsideup

    View Slide

  62. 1.9.x
    • OkHttp by default

    • Windows npipe support

    • Registry auth on Windows

    • Fix local Docker Compose

    on Windows

    • Host ports exposing

    • Random ports in Couchbase
    Sep, 2018
    @bsideup

    View Slide

  63. 1.9.x
    • OkHttp by default

    • Windows npipe support

    • Registry auth on Windows

    • Fix local Docker Compose

    on Windows

    • Host ports exposing

    • Random ports in Couchbase

    • ClickHouse and Postgis modules
    Sep, 2018
    @bsideup

    View Slide

  64. 1.10.x
    Nov, 2018
    @bsideup

    View Slide

  65. 1.10.x
    • JUnit 5 support
    Nov, 2018
    @bsideup
    @Testcontainers
    class MyTestcontainersTests {
    // will be shared between test methods
    @Container
    static final MySQLContainer MYSQL_CONTAINER = new MySQLContainer();
    // will be started before and stopped after each test method
    @Container
    PostgreSQLContainer postgresqlContainer = new PostgreSQLContainer()
    .withDatabaseName("foo")
    .withUsername("foo")
    .withPassword(“secret");
    @Test
    void test() {
    assertTrue(MYSQL_CONTAINER.isRunning());
    assertTrue(postgresqlContainer.isRunning());
    }
    }

    View Slide

  66. 1.10.x
    • JUnit 5 support

    • New docs & more examples
    Nov, 2018
    @bsideup

    View Slide

  67. 1.10.x
    • JUnit 5 support

    • New docs & more examples

    • Env var to turn off Ryuk

    (for public CIs)
    Nov, 2018
    @bsideup

    View Slide

  68. 1.10.x
    • JUnit 5 support

    • New docs & more examples

    • Env var to turn off Ryuk

    (for public CIs)

    • shm + TmpFS settings
    Nov, 2018
    @bsideup

    View Slide

  69. 1.10.x
    • JUnit 5 support

    • New docs & more examples

    • Env var to turn off Ryuk

    (for public CIs)

    • shm + TmpFS settings

    • Auto dependency updates

    with Dependabot
    Nov, 2018
    @bsideup

    View Slide

  70. 1.10.x
    • JUnit 5 support

    • New docs & more examples

    • Env var to turn off Ryuk

    (for public CIs)

    • shm + TmpFS settings

    • Auto dependency updates

    with Dependabot
    Nov, 2018
    @bsideup

    View Slide

  71. 1.10.x
    • JUnit 5 support

    • New docs & more examples

    • Env var to turn off Ryuk

    (for public CIs)

    • shm + TmpFS settings

    • Auto dependency updates

    with Dependabot

    • Neo4j and Elasticsearch modules
    Nov, 2018
    @bsideup

    View Slide

  72. 1.11.x
    Mar, 2019
    @bsideup

    View Slide

  73. 1.11.x
    • Chaos Testing (toxiproxy)
    Mar, 2019
    @bsideup
    @Rule
    public GenericContainer redis = new GenericContainer("redis:5.0.4")
    .withExposedPorts(6379)
    .withNetwork(network);
    @Rule
    public ToxiproxyContainer toxiproxy = new ToxiproxyContainer()
    .withNetwork(network);
    @Test
    public void testLatencyViaProxy() throws IOException {
    ContainerProxy proxy = toxiproxy.getProxy(redis, 6379);
    Jedis jedis = new Jedis(
    proxy.getContainerIpAddress(),
    proxy.getProxyPort()
    );
    proxy.toxics()
    .latency("latency", ToxicDirection.DOWNSTREAM, 1_100)
    .setJitter(100);
    jedis.get("somekey");
    }

    View Slide

  74. 1.11.x
    • Chaos Testing (toxiproxy)

    • fsync=off for PostgreSQL
    Mar, 2019
    @bsideup

    View Slide

  75. 1.11.x
    • Chaos Testing (toxiproxy)

    • fsync=off for PostgreSQL

    • Drop Netty transport
    Mar, 2019
    @bsideup

    View Slide

  76. 1.11.x
    • Chaos Testing (toxiproxy)

    • fsync=off for PostgreSQL

    • Drop Netty transport
    Mar, 2019
    @bsideup

    View Slide

  77. 1.11.x
    • Chaos Testing (toxiproxy)

    • fsync=off for PostgreSQL

    • Drop Netty transport

    • Rework shading
    Mar, 2019
    @bsideup

    View Slide

  78. 1.12.x
    Jul, 2019
    @bsideup

    View Slide

  79. 1.12.x
    • dependsOn
    Jul, 2019
    @bsideup
    @Rule
    KafkaContainer kafka = new KafkaContainer();
    @Rule
    SchemaContainer schemaRegistryContainer = new SchemaContainer()
    .withKafka(kafka)
    .dependsOn(kafka);

    View Slide

  80. 1.12.x
    • dependsOn

    • Improved pull handling
    Jul, 2019
    @bsideup
    11:15:50.598 INFO [ibmcom/db2express-c:latest] - Pulling docker image: ibmcom/db2express-c:latest. Please
    19:34:25.198 INFO [ibmcom/db2express-c:latest] - Pulling image
    19:34:25.198 INFO [ibmcom/db2express-c:latest] - Pulling image layers: 0 pending, 0 downloaded, 0 extr
    19:34:25.967 INFO [ibmcom/db2express-c:latest] - Pulling image layers: 12 pending, 1 downloaded, 0 extr
    19:34:27.363 INFO [ibmcom/db2express-c:latest] - Pulling image layers: 11 pending, 2 downloaded, 0 extr
    19:34:58.519 ERROR [ibmcom/db2express-c:latest] - Docker image pull has not made progress in 30s - abortin
    19:34:58.564 ERROR [ibmcom/db2express-c:latest] - Failed to pull image: ibmcom/db2express-c:latest. Please
    Before:
    After:

    View Slide

  81. 1.12.x
    • dependsOn

    • Improved pull handling

    • Azure Pipelines for Windows testing
    Jul, 2019
    @bsideup

    View Slide

  82. 1.12.x
    • dependsOn

    • Improved pull handling

    • Azure Pipelines for Windows testing
    Jul, 2019
    @bsideup

    View Slide

  83. 1.12.x
    • dependsOn

    • Improved pull handling

    • Azure Pipelines for Windows testing

    • DB2, CockroachDB and RabbitMQ modules
    Jul, 2019
    @bsideup

    View Slide

  84. Roadmap

    View Slide

  85. new DSL

    View Slide

  86. What’s wrong with the current one?

    View Slide

  87. KafkaContainer kafka = new KafkaContainer()
    .withLogConsumer(new Slf4jLogConsumer(log))
    .withEmbeddedZookeeper()
    .withEnv("FOO", "BAR")
    .withStartupAttempts(5);
    Current DSL
    @bsideup

    View Slide

  88. KafkaContainer kafka = new KafkaContainer()
    .withLogConsumer(new Slf4jLogConsumer(log))
    .withEmbeddedZookeeper()
    .withEnv("FOO", "BAR")
    .withStartupAttempts(5);
    Current DSL
    GenericContainer
    @bsideup

    View Slide

  89. KafkaContainer kafka = new KafkaContainer()
    .withLogConsumer(new Slf4jLogConsumer(log))
    .withEmbeddedZookeeper()
    .withEnv("FOO", "BAR")
    .withStartupAttempts(5);
    Current DSL
    KafkaContainer
    @bsideup

    View Slide

  90. KafkaContainer kafka = new KafkaContainer()
    .withLogConsumer(new Slf4jLogConsumer(log))
    .withEmbeddedZookeeper()
    .withEnv("FOO", "BAR")
    .withStartupAttempts(5);
    Current DSL
    GenericContainer
    @bsideup

    View Slide

  91. KafkaContainer kafka = new KafkaContainer()
    .withLogConsumer(new Slf4jLogConsumer(log))
    .withEmbeddedZookeeper()
    .withEnv("FOO", "BAR")
    .withStartupAttempts(5);
    Current DSL
    GenericContainer
    @bsideup

    View Slide

  92. KafkaContainer kafka = new KafkaContainer()
    .withLogConsumer(new Slf4jLogConsumer(log))
    .withEmbeddedZookeeper()
    .withEnv("FOO", "BAR")
    .withStartupAttempts(5);
    Current DSL
    GenericContainer
    public SELF withStartupAttempts(int attempts) {
    this.startupAttempts = attempts;
    return self();
    }
    @bsideup

    View Slide

  93. public class KafkaContainer extends GenericContainer {}
    public class GenericContainer> /* */ {}
    @bsideup

    View Slide

  94. public class KafkaContainer extends GenericContainer {}
    public class GenericContainer> /* */ {}
    https://youtrack.jetbrains.com/issue/KT-17186
    https://stackoverflow.com/questions/39163749/how-to-use-a-java-self-bounded-class-in-scala
    @bsideup

    View Slide

  95. ❌ Hard to maintain
    @bsideup

    View Slide

  96. ❌ Hard to maintain
    ❌ Does not work with Kotlin/Scala
    @bsideup

    View Slide

  97. ❌ Hard to maintain
    ❌ Does not work with Kotlin/Scala
    ❌ Externally mutable objects
    @bsideup

    View Slide

  98. ❌ Hard to maintain
    ❌ Does not work with Kotlin/Scala
    ❌ Externally mutable objects
    ❌ “setX” isn’t supported, only “withX” (think collections)
    @bsideup

    View Slide

  99. ❌ Hard to maintain
    ❌ Does not work with Kotlin/Scala
    ❌ Externally mutable objects
    ❌ “setX” isn’t supported, only “withX” (think collections)
    ❌ No imperative “if-else” with the fluent style
    @bsideup

    View Slide

  100. KafkaContainer kafka = new KafkaContainer() {
    @Override
    protected void initialize() {
    withLogConsumer(new Slf4jLogConsumer(log));
    withEmbeddedZookeeper();
    withEnv("FOO", "BAR");
    withStartupAttempts(5);
    }
    };
    New “DSL”?
    @bsideup

    View Slide

  101. KafkaContainer kafka = new KafkaContainer() {
    @Override
    protected void initialize() {
    withLogConsumer(new Slf4jLogConsumer(log));
    withEmbeddedZookeeper();
    withEnv("FOO", "BAR");
    withStartupAttempts(5);
    }
    };
    New “DSL”?
    Or even…
    @bsideup

    View Slide

  102. KafkaContainer kafka = new KafkaContainer() {{
    withLogConsumer(new Slf4jLogConsumer(log));
    withEmbeddedZookeeper();
    withEnv("FOO", "BAR");
    withStartupAttempts(5);
    }}
    New “DSL”?
    @bsideup

    View Slide

  103. KafkaContainer kafka = new KafkaContainer() {{
    withLogConsumer(new Slf4jLogConsumer(log));
    withEmbeddedZookeeper();
    withEnv("FOO", "BAR");
    withStartupAttempts(5);
    }}
    New “DSL”?
    public void withStartupAttempts(int attempts) {
    this.startupAttempts = attempts;
    }
    @bsideup

    View Slide

  104. KafkaContainer kafka = new KafkaContainer() {{
    withLogConsumer(new Slf4jLogConsumer(log));
    withEmbeddedZookeeper();
    withEnv("FOO", "BAR");
    withStartupAttempts(5);
    }}
    New “DSL”?
    public void withStartupAttempts(int attempts) {
    this.startupAttempts = attempts;
    }
    @bsideup

    View Slide

  105. ✓ Super easy to maintain
    @bsideup

    View Slide

  106. ✓ Super easy to maintain
    ✓ Works with any JVM language
    @bsideup

    View Slide

  107. ✓ Super easy to maintain
    ✓ Works with any JVM language
    ✓ “Controllable mutability” - no modifications outside of
    “initialize”
    @bsideup

    View Slide

  108. ✓ Super easy to maintain
    ✓ Works with any JVM language
    ✓ “Controllable mutability” - no modifications outside of
    “initialize”
    ✓ Void-retuning “setX” can easily be used
    @bsideup

    View Slide

  109. ✓ Super easy to maintain
    ✓ Works with any JVM language
    ✓ “Controllable mutability” - no modifications outside of
    “initialize”
    ✓ Void-retuning “setX” can easily be used
    ✓ Can use “if-else”
    @bsideup

    View Slide

  110. GraalVM focus

    View Slide

  111. @bsideup
    https://medium.com/graalvm/using-testcontainers-from-a-node-js-
    application-3aa2273bf3bb

    View Slide

  112. @bsideup
    // JavaScript
    var GenericContainer = Java.type(’org.testcontainers.containers.GenericContainer’);
    var container = new GenericContainer("nginx");
    container.setExposedPorts([80]);
    container.start();
    console.log(container.getContainerIpAddress() + ‘:’ + container.getMappedPort(80));
    https://medium.com/graalvm/using-testcontainers-from-a-node-js-
    application-3aa2273bf3bb

    View Slide

  113. @bsideup
    // JavaScript
    var GenericContainer = Java.type(’org.testcontainers.containers.GenericContainer’);
    var container = new GenericContainer("nginx");
    container.setExposedPorts([80]);
    container.start();
    console.log(container.getContainerIpAddress() + ‘:’ + container.getMappedPort(80));
    https://medium.com/graalvm/using-testcontainers-from-a-node-js-
    application-3aa2273bf3bb
    // Python
    import java
    generic = java.type('org.testcontainers.containers.GenericContainer')
    container = generic('nginx')
    container.setExposedPorts([80])
    container.start();
    print('%s:%s' % (container.getContainerIpAddress(), container.getMappedPort(80)));

    View Slide

  114. “container core”

    View Slide

  115. Testcontainers 1.x architecture
    Core

    (Docker, GenericContainer, 

    JUnit 4 int, test lifecycle)
    @bsideup

    View Slide

  116. Testcontainers 1.x architecture
    Core

    (Docker, GenericContainer, 

    JUnit 4 int, test lifecycle)
    JUnit Jupiter int.
    @bsideup

    View Slide

  117. Testcontainers 1.x architecture
    Core

    (Docker, GenericContainer, 

    JUnit 4 int, test lifecycle)
    JUnit Jupiter int.
    Modules like MySQL/Kafka/…
    @bsideup

    View Slide

  118. Testcontainers 2.x architecture
    Container-core

    (Container)
    @bsideup

    View Slide

  119. Testcontainers 2.x architecture
    Container-core

    (Container)
    Test Frameworks
    JUnit 4
    JUnit Jupiter
    Scala test?

    @bsideup

    View Slide

  120. Testcontainers 2.x architecture
    Container-core

    (Container)
    Test Frameworks
    JUnit 4
    JUnit Jupiter
    Scala test?

    Executing engines
    Container-core-docker

    (env discovery, networks, …)
    Container-core-k8s?

    @bsideup

    View Slide

  121. Modules like MySQL/Kafka/…
    Testcontainers 2.x architecture
    Container-core

    (Container)
    Test Frameworks
    JUnit 4
    JUnit Jupiter
    Scala test?

    Executing engines
    Container-core-docker

    (env discovery, networks, …)
    Container-core-k8s?

    @bsideup

    View Slide

  122. View Slide

  123. Usability
    Flexibility
    Speed
    Features
    @bsideup

    View Slide

  124. Usability
    Flexibility
    Speed
    Features
    @bsideup

    View Slide

  125. Usability
    Flexibility
    Speed
    Features
    @bsideup

    View Slide

  126. Please welcome…

    View Slide

  127. Reusable
    containers

    View Slide

  128. Reusable
    containers

    View Slide

  129. Demo

    View Slide

  130. @bsideup

    View Slide

  131. ✓ Ultra-fast ITDD (Integration Test Driven Development)
    @bsideup

    View Slide

  132. ✓ Ultra-fast ITDD (Integration Test Driven Development)
    ✓ Minimal effort for the users
    @bsideup

    View Slide

  133. ✓ Ultra-fast ITDD (Integration Test Driven Development)
    ✓ Minimal effort for the users
    ✓ Works for most of the containers
    @bsideup

    View Slide

  134. ✓ Ultra-fast ITDD (Integration Test Driven Development)
    ✓ Minimal effort for the users
    ✓ Works for most of the containers
    ✓ Eventually cleanups stale containers

    (unlike Docker Compose)
    @bsideup

    View Slide

  135. ✓ Ultra-fast ITDD (Integration Test Driven Development)
    ✓ Minimal effort for the users
    ✓ Works for most of the containers
    ✓ Eventually cleanups stale containers

    (unlike Docker Compose)
    ✓ The alpha version is available NOW (v1.12.3+)
    @bsideup

    View Slide

  136. Takeaways
    • https://testcontainers.org
    • Works on Linux, Mac and Windows
    • …including CIs like Jenkins, Travis, CircleCI, GH Actions, Azure Pipelines, …

    • Provides a great balance between 

    flexibility, usability, speed and features

    @bsideup

    View Slide

  137. @bsideup
    bsideup

    View Slide