Integration Testing with
Testcontainers
-
Software Engineer @ AtomicJar
- PhD Student @ RWTH Aachen
- Coach & Trainer @ Styrascosoft
- Testcontainers Maintainer and Open Source Enthusiast
- Oracle Groundbreaker Ambassador
Kevin Wittek @kiview
Why do we Test?
Key learnings
- Easy setup of complete test environments
- Not a lot effort to integration test using real external applications
- Avoid integrated tests!
$ git clone https://github.com/foo/bar.git
$ cd bar
$ ./gradlew build
Pyramid of the Sun
Visoko, Bosnia
My definiton
For example:
- Launch application server
- Framework/Library interactions
- Interact with external processes (e.g. over the network, file system, database)
"Tests which interact with external systems/dependencies"
But why a pyramid?
Testing Honeycomb
Integration Testing transformation over the years
Why combine?
- Easy setup of dev environment
- Uniform build and test environments
- Also self contained and portable!
- No installation and setup of external software
- Except Docker 😜
GenericContainer redis =
new GenericContainer(
"redis:5.0.3-alpine"
).withExposedPorts(6379);
redis.start();
// test my stuff
redis.stop();
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.16.2</version>
<scope>test</scope>
</dependency>
testImplementation "org.testcontainers:testcontainers:1.16.2"
The Project
- testcontainers-java first released in 2015
- 100% OSS, MIT licensed
- 52 releases, 305 contributors
- Core maintainers
- Richard North
- Sergei Egorov
- Kevin Wittek
- Forks in Python, C#, Rust, Go, JS; Scala wrapper (+ unofficial Clojure wrapper )
@whichrich
Capabilities
- Generic docker container support
- use any Docker image to support tests
- Databases (many!) and Stream processing (Kafka, Pulsar)
- AWS, Azure and GCloud mocks (e.g., Localstack)
- Docker Compose
- Or as a Docker Compose alternative!
- Selenium
- Chaos testing (toxiproxy)
Capabilities (2)
- Dynamic port binding and API
- WaitStrategies
- Docker environment discovery (e.g. docker-machine, DOCKER_HOST, Docker for Mac, Docker for Windows)
- Platform independent
- Linux, macOS, Windows 10 (with NPIPE support!)
Support all Major CI Systems!
- Jenkins
- TravisCI
- GitlabCI
- CircleCI
- Azure DevOps Pipelines
- Bitbucket
- GitHub Actions
- ...
@Rule
public GenericContainer redis =
new GenericContainer(
"redis:5.0.3-alpine"
).withExposedPorts(6379);
JUnit4 Rules
Spock Extension
@Testcontainers
class TestContainersClassIT extends Specification {
@Shared
GenericContainer redis =
new GenericContainer("redis:5.0.3-alpine")
.withExposedPorts(6379)
// tests here
}
Testcontainers-Jupiter (JUnit5)
@Testcontainers
class SomeTest {
@Container
public GenericContainer redis =
new GenericContainer(
"redis:5.0.3-alpine"
).withExposedPorts(6379);
// test methods
}
DOs
- Use Testcontainers
- Use copyFileToContainer
DONT's
- Use fixed host ports
- Disable Ryuk without understanding the implications
- Assume Podman is a Docker drop-in replacement
Singleton Container Pattern
abstract class AbstractContainerBaseTest {
static final MySQLContainer MY_SQL_CONTAINER;
static {
MY_SQL_CONTAINER = new MySQLContainer();
MY_SQL_CONTAINER.start();
}
}
class FirstTest extends AbstractContainerBaseTest {
@Test
void someTestMethod() {
String url = MY_SQL_CONTAINER.getJdbcUrl();
// create a connection and run test as normal
}
}
Testcontainers 1.16.1
Testcontainers 1.16.2
Docker-Compose
version: "3"
services:
vote:
image: vote-frontend
command: python app.py
volumes:
- ./vote:/app
ports:
- "5000:80"
redis:
image: redis:alpine
ports: ["6379"]
worker:
image: worker
db:
image: postgres:9.4
result:
image: result-frontend
command: nodemon --debug server.js
volumes:
- ./result:/app
ports:
- "5001:80"
- "5858:5858"
TC as a DockerCompose replacement
TDD workflows
- Container startup introduces overhead
- Testcontainers should be ephemeral
- We still want to avoid test pollution and integrated tests
The Future?
- New builder DSL
- Container-Core
- Test-Framework agnostic
- OO abstraction of Docker containers
- Other languages
- More languages and aligning existing fork
- Stay tuned for AtomicJar news!
Testcontainers APACOUC
By Kevin Wittek
Testcontainers APACOUC
- 905