SlideShare a Scribd company logo
1 of 48
Download to read offline
Level Up Your Integration Testing
With Testcontainers
Dan Vega ⸱ @therealdanvega
Developer Advocate, VMware
⸺
Cora Iberkleid ⸱ @ciberkleid
Developer Advocate, VMware
⸺
Maria Gabriella Brodi ⸱ @BrodiMg
Staff Solutions Engineer, VMware
Abstract - SpringOne Tour
Traditional approaches to integration testing—using shared, local, or in-memory databases—fall short for
today's modern developer.
Developers today are building cloud native distributed microservices and taking advantage of a rich variety
of backing services. This explosion of applications and backing services introduces new challenges in
creating the necessary environments for integration testing. To be useful and effective, these environments
must be easy to create and they must resemble production as closely as possible. New solutions are needed
to make this need a reality.
Enter Testcontainers!
Testcontainers is a Java library that supports JUnit tests and makes it incredibly easy to create lightweight,
throwaway instances of common databases, Selenium web browsers, or anything else that can run in a
Docker container.
Testing is important
Testing can be hard
“You have to make the
right thing to do, the easy
thing to do.”
- Cora Iberkleid
Agenda
● Intro
● Testcontainers 101
● Spring Boot Demo
● Q&A
INTRO
“Prod-like” integration testing - what do we mean?
● Integration vs Unit tests
● Greater fidelity to run-time conditions
○ Type of system
○ Network reliability
○ OS environment
● Shifted left
○ Local developer machine
○ Iterate locally
Common approaches to integration testing
In Integration tests we are interested in verifying the behavior and interactions of
multiple modules.
For this purpose we can use:
● Shared instances
● Local installation
● In memory solutions
In-memory testing
App
Mock server or
in-memory service
Options:
● Mock server (Wiremock, Loki…)
● In-memory service (h2, hsql...)
Limitations of in-memory testing
App
Mock server or
in-memory service
Limitations:
● Requires framework support
● Behavior differences to real system
● Latency/bandwidth testing can be
challenging
● Not every service has an in-memory
option
● Differences in security configuration
New challenges with in-memory testing
App
Challenge exacerbated with explosion in microservices
and variety of service options over the last 10 years.
Mock server or
in-memory service
Limitations:
● Requires framework support
● Behavior differences to real system
● Latency/bandwidth testing can be
challenging
● Not every service has an in-memory
option
● Differences in security configuration
New challenges with in-memory testing
App
Challenge exacerbated with explosion in microservices
and variety of service options over the last 10 years.
Mock server or
in-memory service
Limitations:
● Requires framework support
● Behavior differences to real system
● Latency/bandwidth testing can be
challenging
● Not every service has an in-memory
option
● Differences in security configuration
Containerization Helps!
● Containerization per se is a big part of the solution
● Docker Compose - works for any framework
However…
● Cumbersome lifecycle management
● Additional skill set for developers to learn
However!
● There is an easier solution :)
Testcontainers: easy testing with external services
Service on Docker
App
Testcontainers
dependency
TESTCONTAINERS 101
Testcontainers intro/overview
● Java library that creates instances of Docker containers for testing
● Supports JUnit4, JUnit5, and Spock
Support for other languages
(check GitHub for more complete information)
Available modules
● Provides lightweight,
throwaway instances of
common databases,
Selenium web browsers,
and more
● Can start anything else
that can run in a Docker
container
● Can run containers on
your local Docker or in
the Testcontainers Cloud
SaaS platform (beta)
Available modules
● Provides lightweight,
throwaway instances of
common databases,
Selenium web browsers,
and more
Available modules
● Provides lightweight,
throwaway instances of
common databases,
Selenium web browsers,
and more
Available modules
● Provides lightweight,
throwaway instances of
common databases,
Selenium web browsers,
and more
Available modules
● Provides lightweight,
throwaway instances of
common databases,
Selenium web browsers,
and more
Available modules
● Provides lightweight,
throwaway instances of
common databases,
Selenium web browsers,
and more
Available modules
● Provides lightweight,
throwaway instances of
common databases,
Selenium web browsers,
and more
Available modules
● Provides lightweight,
throwaway instances of
common databases,
Selenium web browsers,
and more
Available modules
● Provides lightweight,
throwaway instances of
common databases,
Selenium web browsers,
and more
● Can start anything else
that can run in a Docker
container
Whale by Artzgeo on Noun Project
And in the
cloud!
Testcontainers
Cloud
SaaS Platform (beta)
https:/
/testcontainers.cloud
Photo by Engin Akyurt on Unsplash
Whale by Artzgeo on Noun Project
X
Why Testcontainers? Where to use them?
● Prod-like systems:
● Easier instantiation of disposable services that lack an in-memory option
● Test against any application that can run as a container
● Integration testing:
● Data access layer integration
● Application integration
● Browser-based acceptance
inspiration...
package org.testcontainers.junit.jupiter;
import ...
class TestcontainersExtension implements BeforeEachCallback, BeforeAllCallback,
AfterEachCallback, AfterAllCallback, ExecutionCondition, TestInstancePostProcessor {
@Testcontainers (JUnit 5)
JUnit5 Extension - intercepts JUnit lifecycle
events and manages container lifecycles
@Testcontainers
public class MyIntegrationTests {
@Container // In JUnit 4, use @Rule/@ClassRule
static PostgreSQLContainer<?> db = new PostgreSQLContainer<>("postgres");
...
@ExtendWith({TestcontainersExtension.class})
@Container (JUnit 5) / @Rule (JUnit 4)
@Testcontainers
public class MyIntegrationTests {
@Container // In JUnit 4, use @Rule/@ClassRule
PostgreSQLContainer<?> db = new PostgreSQLContainer<>("postgres");
...
Flags TestcontainersExtension about a container to manage
● New container is started/stopped for every test
● Declare as static to re-use the same container
JUnit Test Lifecycle & Testcontainer Callbacks
BeforeAllCallback
BeforeEachCallback
AfterAllCallback
AfterEachCallback
ExecutionCondition
TestInstancePostProcessor
JUnit Test Lifecycle
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
In @BeforeAll. Static method.
No testcontainers
default action in
@BeforeAll
Test 1
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
In @BeforeAll. Static method.
In Constructor. Class instance: LifeCycleTest@17d88132
No testcontainers action
in Constructor
Test 1
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
In @BeforeAll. Static method.
In Constructor. Class instance: LifeCycleTest@17d88132
Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
Connected to docker
Pulling docker image: testcontainers/ryuk
Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
Checking the system...
✔ Docker server version should be at least 1.6.0
✔ Docker environment should have more than 2GB free disk space
Pulling docker image: myRepo/myImg
Container myRepo/myImg is starting:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
@BeforeEach, Test1:
Connect to docker
Start ryuk
Check system
Start container
Execute BeforeEach method
Test 1
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
In @BeforeAll. Static method.
In Constructor. Class instance: LifeCycleTest@17d88132
Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
Connected to docker
Pulling docker image: testcontainers/ryuk
Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
Checking the system...
✔ Docker server version should be at least 1.6.0
✔ Docker environment should have more than 2GB free disk space
Pulling docker image: myRepo/myImg
Container myRepo/myImg is starting:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @Test 1. Class instance: LifeCycleTest@17d88132
No testcontainers action
in @Test
Test 1
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
In @BeforeAll. Static method.
In Constructor. Class instance: LifeCycleTest@17d88132
Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
Connected to docker
Pulling docker image: testcontainers/ryuk
Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
Checking the system...
✔ Docker server version should be at least 1.6.0
✔ Docker environment should have more than 2GB free disk space
Pulling docker image: myRepo/myImg
Container myRepo/myImg is starting:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @Test 1. Class instance: LifeCycleTest@17d88132
In @AfterEach. Class instance: LifeCycleTest@17d88132
Ryuk removed container and associated volume(s): myRepo/myImg
After Test 1 “AfterEach”,
Ryuk cleans up container
Test 1
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
In @BeforeAll. Static method.
In Constructor. Class instance: LifeCycleTest@17d88132
Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
Connected to docker
Pulling docker image: testcontainers/ryuk
Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
Checking the system...
✔ Docker server version should be at least 1.6.0
✔ Docker environment should have more than 2GB free disk space
Pulling docker image: myRepo/myImg
Container myRepo/myImg is starting:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @Test 1. Class instance: LifeCycleTest@17d88132
In @AfterEach. Class instance: LifeCycleTest@17d88132
Ryuk removed container and associated volume(s): myRepo/myImg
In Constructor. Class instance: LifeCycleTest@42d236fb
Constructor creates a
new class instance
Test 2
Test 1
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
In @BeforeAll. Static method.
In Constructor. Class instance: LifeCycleTest@17d88132
Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
Connected to docker
Pulling docker image: testcontainers/ryuk
Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
Checking the system...
✔ Docker server version should be at least 1.6.0
✔ Docker environment should have more than 2GB free disk space
Pulling docker image: myRepo/myImg
Container myRepo/myImg is starting:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @Test 1. Class instance: LifeCycleTest@17d88132
In @AfterEach. Class instance: LifeCycleTest@17d88132
Ryuk removed container and associated volume(s): myRepo/myImg
In Constructor. Class instance: LifeCycleTest@42d236fb
Container myRepo/myImg is starting:
20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1
In @BeforeEach. Class instance: LifeCycleTest@42d236fb, Container id:
20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1
@BeforeEach, Test2:
Start new container
Execute BeforeEach method
Test 2
Test 1
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
In @BeforeAll. Static method.
In Constructor. Class instance: LifeCycleTest@17d88132
Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
Connected to docker
Pulling docker image: testcontainers/ryuk
Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
Checking the system...
✔ Docker server version should be at least 1.6.0
✔ Docker environment should have more than 2GB free disk space
Pulling docker image: myRepo/myImg
Container myRepo/myImg is starting:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @Test 1. Class instance: LifeCycleTest@17d88132
In @AfterEach. Class instance: LifeCycleTest@17d88132
Ryuk removed container and associated volume(s): myRepo/myImg
In Constructor. Class instance: LifeCycleTest@42d236fb
Container myRepo/myImg is starting:
20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1
In @BeforeEach. Class instance: LifeCycleTest@42d236fb, Container id:
20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1
In @Test 2. Class instance: LifeCycleTest@42d236fb
No testcontainers action
in @Test
Test 2
Test 1
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
In @BeforeAll. Static method.
In Constructor. Class instance: LifeCycleTest@17d88132
Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
Connected to docker
Pulling docker image: testcontainers/ryuk
Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
Checking the system...
✔ Docker server version should be at least 1.6.0
✔ Docker environment should have more than 2GB free disk space
Pulling docker image: myRepo/myImg
Container myRepo/myImg is starting:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @Test 1. Class instance: LifeCycleTest@17d88132
In @AfterEach. Class instance: LifeCycleTest@17d88132
Ryuk removed container and associated volume(s): myRepo/myImg
In Constructor. Class instance: LifeCycleTest@42d236fb
Container myRepo/myImg is starting:
20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1
In @BeforeEach. Class instance: LifeCycleTest@42d236fb, Container id:
20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1
In @Test 2. Class instance: LifeCycleTest@42d236fb
In @AfterEach. Class instance: LifeCycleTest@42d236fb
Ryuk removed container and associated volume(s): myRepo/myImg
In @AfterAll. Static method.
After Test 2 “AfterEach”,
Ryuk cleans up container
Test 2
Test 1
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
In @BeforeAll. Static method.
In Constructor. Class instance: LifeCycleTest@17d88132
Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
Connected to docker
Pulling docker image: testcontainers/ryuk
Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
Checking the system...
✔ Docker server version should be at least 1.6.0
✔ Docker environment should have more than 2GB free disk space
Pulling docker image: myRepo/myImg
Container myRepo/myImg is starting:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id:
b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5
In @Test 1. Class instance: LifeCycleTest@17d88132
In @AfterEach. Class instance: LifeCycleTest@17d88132
Ryuk removed container and associated volume(s): myRepo/myImg
In Constructor. Class instance: LifeCycleTest@42d236fb
Container myRepo/myImg is starting:
20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1
In @BeforeEach. Class instance: LifeCycleTest@42d236fb, Container id:
20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1
In @Test 2. Class instance: LifeCycleTest@42d236fb
In @AfterEach. Class instance: LifeCycleTest@42d236fb
Ryuk removed container and associated volume(s): myRepo/myImg
In @AfterAll. Static method.
No testcontainers
default action in
@AfterAll
Test 2
Test 1
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
static GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
@Testcontainers
@Slf4j
public class LifeCycleTest {
@Container
static GenericContainer container = new
GenericContainer(DockerImageName.parse("myRepo/myImg"));
public LifeCycleTest() {
log.info("In Constructor. Class instance: ", this);
}
@BeforeAll
public static void beforeAllMethod() {
log.info("In @BeforeAll. Static method.");
}
@BeforeEach
public void beforeEachMethod() {
log.info("In @BeforeEach. Class instance: " + this
+ ", Container id: ", container.getContainerId());
}
@Test
public void test1() {
log.info("In @Test 1. Class instance: ", this);
}
@Test
public void test2() {
log.info("In @Test 2. Class instance: ", this);
}
@AfterEach
public void afterEachMethod() {
log.info("In @AfterEach. Class instance: ", this);
}
@AfterAll
public static void afterAllMethod() {
log.info("In @AfterAll. Static method.");
}
}
Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
Connected to docker
Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
Checking the system...
✔ Docker server version should be at least 1.6.0
✔ Docker environment should have more than 2GB free disk space
Container myRepo/myImg is starting:
8d8ff20a9f25dd8b0d4cd025406bdebfa9dcf5ab637ef53b5a815d97bc739b5a
In @BeforeAll. Static method.
In Constructor. Class instance: LifeCycleTest@63a5d002
In @BeforeEach. Class instance: LifeCycleTest@63a5d002, Container id:
8d8ff20a9f25dd8b0d4cd025406bdebfa9dcf5ab637ef53b5a815d97bc739b5a
In @Test 1. Class instance: LifeCycleTest@63a5d002
In @AfterEach. Class instance: LifeCycleTest@63a5d002
In Constructor. Class instance: LifeCycleTest@60e949e1
In @BeforeEach. Class instance: LifeCycleTest@60e949e1, Container id:
8d8ff20a9f25dd8b0d4cd025406bdebfa9dcf5ab637ef53b5a815d97bc739b5a
In @Test 2. Class instance: LifeCycleTest@60e949e1
In @AfterEach. Class instance: LifeCycleTest@60e949e1
In @AfterAll. Static method.
Ryuk removed container and associated volume(s): myRepo/myImg
Container is reused
across tests
Test 2
Test 1
Spring Boot ❤ Testcontainers
https://github.com/danvega/reading-list
Q&A

More Related Content

What's hot

What Is A Docker Container? | Docker Container Tutorial For Beginners| Docker...
What Is A Docker Container? | Docker Container Tutorial For Beginners| Docker...What Is A Docker Container? | Docker Container Tutorial For Beginners| Docker...
What Is A Docker Container? | Docker Container Tutorial For Beginners| Docker...
Simplilearn
 

What's hot (20)

What Is A Docker Container? | Docker Container Tutorial For Beginners| Docker...
What Is A Docker Container? | Docker Container Tutorial For Beginners| Docker...What Is A Docker Container? | Docker Container Tutorial For Beginners| Docker...
What Is A Docker Container? | Docker Container Tutorial For Beginners| Docker...
 
React
React React
React
 
Introduction to Redux
Introduction to ReduxIntroduction to Redux
Introduction to Redux
 
presentation on Docker
presentation on Dockerpresentation on Docker
presentation on Docker
 
React js programming concept
React js programming conceptReact js programming concept
React js programming concept
 
Understanding react hooks
Understanding react hooksUnderstanding react hooks
Understanding react hooks
 
React js
React jsReact js
React js
 
Redux Toolkit - Quick Intro - 2022
Redux Toolkit - Quick Intro - 2022Redux Toolkit - Quick Intro - 2022
Redux Toolkit - Quick Intro - 2022
 
Spring Boot Interview Questions | Edureka
Spring Boot Interview Questions | EdurekaSpring Boot Interview Questions | Edureka
Spring Boot Interview Questions | Edureka
 
Testcontainers - Geekout EE 2017 presentation
Testcontainers - Geekout EE 2017 presentationTestcontainers - Geekout EE 2017 presentation
Testcontainers - Geekout EE 2017 presentation
 
React native
React nativeReact native
React native
 
Hexagonal architecture in PHP
Hexagonal architecture in PHPHexagonal architecture in PHP
Hexagonal architecture in PHP
 
Functional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User GroupFunctional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User Group
 
Solid principles
Solid principlesSolid principles
Solid principles
 
DevOps Sonatype Nexus Demo_2023.pdf
DevOps Sonatype Nexus Demo_2023.pdfDevOps Sonatype Nexus Demo_2023.pdf
DevOps Sonatype Nexus Demo_2023.pdf
 
ES6 presentation
ES6 presentationES6 presentation
ES6 presentation
 
Why and How to Use Virtual DOM
Why and How to Use Virtual DOMWhy and How to Use Virtual DOM
Why and How to Use Virtual DOM
 
React web development
React web developmentReact web development
React web development
 
JUnit & Mockito, first steps
JUnit & Mockito, first stepsJUnit & Mockito, first steps
JUnit & Mockito, first steps
 
Docker: From Zero to Hero
Docker: From Zero to HeroDocker: From Zero to Hero
Docker: From Zero to Hero
 

Similar to Level Up Your Integration Testing With Testcontainers

Cerberus_Presentation1
Cerberus_Presentation1Cerberus_Presentation1
Cerberus_Presentation1
CIVEL Benoit
 
Into The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applicationsInto The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applications
Ortus Solutions, Corp
 
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
NaviAningi
 

Similar to Level Up Your Integration Testing With Testcontainers (20)

Prod-Like Integration Testing for Distributed Containerized Applications
Prod-Like Integration Testing for Distributed Containerized ApplicationsProd-Like Integration Testing for Distributed Containerized Applications
Prod-Like Integration Testing for Distributed Containerized Applications
 
JLove - Replicating production on your laptop using the magic of containers
JLove - Replicating production on your laptop using the magic of containersJLove - Replicating production on your laptop using the magic of containers
JLove - Replicating production on your laptop using the magic of containers
 
JBCN_Testing_With_Containers
JBCN_Testing_With_ContainersJBCN_Testing_With_Containers
JBCN_Testing_With_Containers
 
Anatomy of a Build Pipeline
Anatomy of a Build PipelineAnatomy of a Build Pipeline
Anatomy of a Build Pipeline
 
Advanced Java Testing
Advanced Java TestingAdvanced Java Testing
Advanced Java Testing
 
Easy Java Integration Testing with Testcontainers​
Easy Java Integration Testing with Testcontainers​Easy Java Integration Testing with Testcontainers​
Easy Java Integration Testing with Testcontainers​
 
Ensuring OpenStack Version up Compatibility for CloudOpen Japan 2013-05-31
Ensuring OpenStack Version up Compatibility for CloudOpen Japan 2013-05-31Ensuring OpenStack Version up Compatibility for CloudOpen Japan 2013-05-31
Ensuring OpenStack Version up Compatibility for CloudOpen Japan 2013-05-31
 
Throwing complexity over the wall: Rapid development for enterprise Java (Jav...
Throwing complexity over the wall: Rapid development for enterprise Java (Jav...Throwing complexity over the wall: Rapid development for enterprise Java (Jav...
Throwing complexity over the wall: Rapid development for enterprise Java (Jav...
 
Slow, Flaky and Legacy Tests: FTFY - Our New Testing Strategy at Net-A-Porter...
Slow, Flaky and Legacy Tests: FTFY - Our New Testing Strategy at Net-A-Porter...Slow, Flaky and Legacy Tests: FTFY - Our New Testing Strategy at Net-A-Porter...
Slow, Flaky and Legacy Tests: FTFY - Our New Testing Strategy at Net-A-Porter...
 
Cerberus : Framework for Manual and Automated Testing (Web Application)
Cerberus : Framework for Manual and Automated Testing (Web Application)Cerberus : Framework for Manual and Automated Testing (Web Application)
Cerberus : Framework for Manual and Automated Testing (Web Application)
 
Cerberus_Presentation1
Cerberus_Presentation1Cerberus_Presentation1
Cerberus_Presentation1
 
How to Build Your Own Test Automation Framework?
How to Build Your Own Test Automation Framework?How to Build Your Own Test Automation Framework?
How to Build Your Own Test Automation Framework?
 
Into The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applicationsInto The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applications
 
Droidcon Spain 2016 - The Pragmatic Android Programmer: from hype to reality
 Droidcon Spain 2016 - The Pragmatic Android Programmer: from hype to reality Droidcon Spain 2016 - The Pragmatic Android Programmer: from hype to reality
Droidcon Spain 2016 - The Pragmatic Android Programmer: from hype to reality
 
Resilience Testing
Resilience Testing Resilience Testing
Resilience Testing
 
Cloud Native Dünyada CI/CD
Cloud Native Dünyada CI/CDCloud Native Dünyada CI/CD
Cloud Native Dünyada CI/CD
 
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
 
KKSD_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
KKSD_Testbirds_Selenium_eclipsecon_FINAL_0.pptKKSD_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
KKSD_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
 
New types of tests for Java projects
New types of tests for Java projectsNew types of tests for Java projects
New types of tests for Java projects
 
Creating Realistic Unit Tests with Testcontainers
Creating Realistic Unit Tests with TestcontainersCreating Realistic Unit Tests with Testcontainers
Creating Realistic Unit Tests with Testcontainers
 

More from VMware Tanzu

More from VMware Tanzu (20)

What AI Means For Your Product Strategy And What To Do About It
What AI Means For Your Product Strategy And What To Do About ItWhat AI Means For Your Product Strategy And What To Do About It
What AI Means For Your Product Strategy And What To Do About It
 
Make the Right Thing the Obvious Thing at Cardinal Health 2023
Make the Right Thing the Obvious Thing at Cardinal Health 2023Make the Right Thing the Obvious Thing at Cardinal Health 2023
Make the Right Thing the Obvious Thing at Cardinal Health 2023
 
Enhancing DevEx and Simplifying Operations at Scale
Enhancing DevEx and Simplifying Operations at ScaleEnhancing DevEx and Simplifying Operations at Scale
Enhancing DevEx and Simplifying Operations at Scale
 
Spring Update | July 2023
Spring Update | July 2023Spring Update | July 2023
Spring Update | July 2023
 
Platforms, Platform Engineering, & Platform as a Product
Platforms, Platform Engineering, & Platform as a ProductPlatforms, Platform Engineering, & Platform as a Product
Platforms, Platform Engineering, & Platform as a Product
 
Building Cloud Ready Apps
Building Cloud Ready AppsBuilding Cloud Ready Apps
Building Cloud Ready Apps
 
Spring Boot 3 And Beyond
Spring Boot 3 And BeyondSpring Boot 3 And Beyond
Spring Boot 3 And Beyond
 
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdf
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdfSpring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdf
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdf
 
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
 
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
 
tanzu_developer_connect.pptx
tanzu_developer_connect.pptxtanzu_developer_connect.pptx
tanzu_developer_connect.pptx
 
Tanzu Virtual Developer Connect Workshop - French
Tanzu Virtual Developer Connect Workshop - FrenchTanzu Virtual Developer Connect Workshop - French
Tanzu Virtual Developer Connect Workshop - French
 
Tanzu Developer Connect Workshop - English
Tanzu Developer Connect Workshop - EnglishTanzu Developer Connect Workshop - English
Tanzu Developer Connect Workshop - English
 
Virtual Developer Connect Workshop - English
Virtual Developer Connect Workshop - EnglishVirtual Developer Connect Workshop - English
Virtual Developer Connect Workshop - English
 
Tanzu Developer Connect - French
Tanzu Developer Connect - FrenchTanzu Developer Connect - French
Tanzu Developer Connect - French
 
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023
 
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring Boot
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring BootSpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring Boot
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring Boot
 
SpringOne Tour: The Influential Software Engineer
SpringOne Tour: The Influential Software EngineerSpringOne Tour: The Influential Software Engineer
SpringOne Tour: The Influential Software Engineer
 
SpringOne Tour: Domain-Driven Design: Theory vs Practice
SpringOne Tour: Domain-Driven Design: Theory vs PracticeSpringOne Tour: Domain-Driven Design: Theory vs Practice
SpringOne Tour: Domain-Driven Design: Theory vs Practice
 
SpringOne Tour: Spring Recipes: A Collection of Common-Sense Solutions
SpringOne Tour: Spring Recipes: A Collection of Common-Sense SolutionsSpringOne Tour: Spring Recipes: A Collection of Common-Sense Solutions
SpringOne Tour: Spring Recipes: A Collection of Common-Sense Solutions
 

Recently uploaded

%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
chiefasafspells
 

Recently uploaded (20)

%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 

Level Up Your Integration Testing With Testcontainers

  • 1. Level Up Your Integration Testing With Testcontainers Dan Vega ⸱ @therealdanvega Developer Advocate, VMware ⸺ Cora Iberkleid ⸱ @ciberkleid Developer Advocate, VMware ⸺ Maria Gabriella Brodi ⸱ @BrodiMg Staff Solutions Engineer, VMware
  • 2. Abstract - SpringOne Tour Traditional approaches to integration testing—using shared, local, or in-memory databases—fall short for today's modern developer. Developers today are building cloud native distributed microservices and taking advantage of a rich variety of backing services. This explosion of applications and backing services introduces new challenges in creating the necessary environments for integration testing. To be useful and effective, these environments must be easy to create and they must resemble production as closely as possible. New solutions are needed to make this need a reality. Enter Testcontainers! Testcontainers is a Java library that supports JUnit tests and makes it incredibly easy to create lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
  • 5. “You have to make the right thing to do, the easy thing to do.” - Cora Iberkleid
  • 6. Agenda ● Intro ● Testcontainers 101 ● Spring Boot Demo ● Q&A
  • 8. “Prod-like” integration testing - what do we mean? ● Integration vs Unit tests ● Greater fidelity to run-time conditions ○ Type of system ○ Network reliability ○ OS environment ● Shifted left ○ Local developer machine ○ Iterate locally
  • 9. Common approaches to integration testing In Integration tests we are interested in verifying the behavior and interactions of multiple modules. For this purpose we can use: ● Shared instances ● Local installation ● In memory solutions
  • 10. In-memory testing App Mock server or in-memory service Options: ● Mock server (Wiremock, Loki…) ● In-memory service (h2, hsql...)
  • 11. Limitations of in-memory testing App Mock server or in-memory service Limitations: ● Requires framework support ● Behavior differences to real system ● Latency/bandwidth testing can be challenging ● Not every service has an in-memory option ● Differences in security configuration
  • 12. New challenges with in-memory testing App Challenge exacerbated with explosion in microservices and variety of service options over the last 10 years. Mock server or in-memory service Limitations: ● Requires framework support ● Behavior differences to real system ● Latency/bandwidth testing can be challenging ● Not every service has an in-memory option ● Differences in security configuration
  • 13. New challenges with in-memory testing App Challenge exacerbated with explosion in microservices and variety of service options over the last 10 years. Mock server or in-memory service Limitations: ● Requires framework support ● Behavior differences to real system ● Latency/bandwidth testing can be challenging ● Not every service has an in-memory option ● Differences in security configuration
  • 14. Containerization Helps! ● Containerization per se is a big part of the solution ● Docker Compose - works for any framework However… ● Cumbersome lifecycle management ● Additional skill set for developers to learn However! ● There is an easier solution :)
  • 15. Testcontainers: easy testing with external services Service on Docker App Testcontainers dependency
  • 17. Testcontainers intro/overview ● Java library that creates instances of Docker containers for testing ● Supports JUnit4, JUnit5, and Spock
  • 18. Support for other languages (check GitHub for more complete information)
  • 19. Available modules ● Provides lightweight, throwaway instances of common databases, Selenium web browsers, and more ● Can start anything else that can run in a Docker container ● Can run containers on your local Docker or in the Testcontainers Cloud SaaS platform (beta)
  • 20. Available modules ● Provides lightweight, throwaway instances of common databases, Selenium web browsers, and more
  • 21. Available modules ● Provides lightweight, throwaway instances of common databases, Selenium web browsers, and more
  • 22. Available modules ● Provides lightweight, throwaway instances of common databases, Selenium web browsers, and more
  • 23. Available modules ● Provides lightweight, throwaway instances of common databases, Selenium web browsers, and more
  • 24. Available modules ● Provides lightweight, throwaway instances of common databases, Selenium web browsers, and more
  • 25. Available modules ● Provides lightweight, throwaway instances of common databases, Selenium web browsers, and more
  • 26. Available modules ● Provides lightweight, throwaway instances of common databases, Selenium web browsers, and more
  • 27. Available modules ● Provides lightweight, throwaway instances of common databases, Selenium web browsers, and more ● Can start anything else that can run in a Docker container Whale by Artzgeo on Noun Project
  • 28. And in the cloud! Testcontainers Cloud SaaS Platform (beta) https:/ /testcontainers.cloud Photo by Engin Akyurt on Unsplash Whale by Artzgeo on Noun Project X
  • 29. Why Testcontainers? Where to use them? ● Prod-like systems: ● Easier instantiation of disposable services that lack an in-memory option ● Test against any application that can run as a container ● Integration testing: ● Data access layer integration ● Application integration ● Browser-based acceptance
  • 31. package org.testcontainers.junit.jupiter; import ... class TestcontainersExtension implements BeforeEachCallback, BeforeAllCallback, AfterEachCallback, AfterAllCallback, ExecutionCondition, TestInstancePostProcessor { @Testcontainers (JUnit 5) JUnit5 Extension - intercepts JUnit lifecycle events and manages container lifecycles @Testcontainers public class MyIntegrationTests { @Container // In JUnit 4, use @Rule/@ClassRule static PostgreSQLContainer<?> db = new PostgreSQLContainer<>("postgres"); ... @ExtendWith({TestcontainersExtension.class})
  • 32. @Container (JUnit 5) / @Rule (JUnit 4) @Testcontainers public class MyIntegrationTests { @Container // In JUnit 4, use @Rule/@ClassRule PostgreSQLContainer<?> db = new PostgreSQLContainer<>("postgres"); ... Flags TestcontainersExtension about a container to manage ● New container is started/stopped for every test ● Declare as static to re-use the same container
  • 33. JUnit Test Lifecycle & Testcontainer Callbacks BeforeAllCallback BeforeEachCallback AfterAllCallback AfterEachCallback ExecutionCondition TestInstancePostProcessor
  • 34. JUnit Test Lifecycle @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } }
  • 35. @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } In @BeforeAll. Static method. No testcontainers default action in @BeforeAll Test 1
  • 36. @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } In @BeforeAll. Static method. In Constructor. Class instance: LifeCycleTest@17d88132 No testcontainers action in Constructor Test 1
  • 37. @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } In @BeforeAll. Static method. In Constructor. Class instance: LifeCycleTest@17d88132 Found Docker environment with local Unix socket (unix:///var/run/docker.sock) Connected to docker Pulling docker image: testcontainers/ryuk Ryuk started - will monitor and terminate Testcontainers containers on JVM exit Checking the system... ✔ Docker server version should be at least 1.6.0 ✔ Docker environment should have more than 2GB free disk space Pulling docker image: myRepo/myImg Container myRepo/myImg is starting: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 @BeforeEach, Test1: Connect to docker Start ryuk Check system Start container Execute BeforeEach method Test 1
  • 38. @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } In @BeforeAll. Static method. In Constructor. Class instance: LifeCycleTest@17d88132 Found Docker environment with local Unix socket (unix:///var/run/docker.sock) Connected to docker Pulling docker image: testcontainers/ryuk Ryuk started - will monitor and terminate Testcontainers containers on JVM exit Checking the system... ✔ Docker server version should be at least 1.6.0 ✔ Docker environment should have more than 2GB free disk space Pulling docker image: myRepo/myImg Container myRepo/myImg is starting: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @Test 1. Class instance: LifeCycleTest@17d88132 No testcontainers action in @Test Test 1
  • 39. @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } In @BeforeAll. Static method. In Constructor. Class instance: LifeCycleTest@17d88132 Found Docker environment with local Unix socket (unix:///var/run/docker.sock) Connected to docker Pulling docker image: testcontainers/ryuk Ryuk started - will monitor and terminate Testcontainers containers on JVM exit Checking the system... ✔ Docker server version should be at least 1.6.0 ✔ Docker environment should have more than 2GB free disk space Pulling docker image: myRepo/myImg Container myRepo/myImg is starting: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @Test 1. Class instance: LifeCycleTest@17d88132 In @AfterEach. Class instance: LifeCycleTest@17d88132 Ryuk removed container and associated volume(s): myRepo/myImg After Test 1 “AfterEach”, Ryuk cleans up container Test 1
  • 40. @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } In @BeforeAll. Static method. In Constructor. Class instance: LifeCycleTest@17d88132 Found Docker environment with local Unix socket (unix:///var/run/docker.sock) Connected to docker Pulling docker image: testcontainers/ryuk Ryuk started - will monitor and terminate Testcontainers containers on JVM exit Checking the system... ✔ Docker server version should be at least 1.6.0 ✔ Docker environment should have more than 2GB free disk space Pulling docker image: myRepo/myImg Container myRepo/myImg is starting: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @Test 1. Class instance: LifeCycleTest@17d88132 In @AfterEach. Class instance: LifeCycleTest@17d88132 Ryuk removed container and associated volume(s): myRepo/myImg In Constructor. Class instance: LifeCycleTest@42d236fb Constructor creates a new class instance Test 2 Test 1
  • 41. @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } In @BeforeAll. Static method. In Constructor. Class instance: LifeCycleTest@17d88132 Found Docker environment with local Unix socket (unix:///var/run/docker.sock) Connected to docker Pulling docker image: testcontainers/ryuk Ryuk started - will monitor and terminate Testcontainers containers on JVM exit Checking the system... ✔ Docker server version should be at least 1.6.0 ✔ Docker environment should have more than 2GB free disk space Pulling docker image: myRepo/myImg Container myRepo/myImg is starting: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @Test 1. Class instance: LifeCycleTest@17d88132 In @AfterEach. Class instance: LifeCycleTest@17d88132 Ryuk removed container and associated volume(s): myRepo/myImg In Constructor. Class instance: LifeCycleTest@42d236fb Container myRepo/myImg is starting: 20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1 In @BeforeEach. Class instance: LifeCycleTest@42d236fb, Container id: 20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1 @BeforeEach, Test2: Start new container Execute BeforeEach method Test 2 Test 1
  • 42. @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } In @BeforeAll. Static method. In Constructor. Class instance: LifeCycleTest@17d88132 Found Docker environment with local Unix socket (unix:///var/run/docker.sock) Connected to docker Pulling docker image: testcontainers/ryuk Ryuk started - will monitor and terminate Testcontainers containers on JVM exit Checking the system... ✔ Docker server version should be at least 1.6.0 ✔ Docker environment should have more than 2GB free disk space Pulling docker image: myRepo/myImg Container myRepo/myImg is starting: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @Test 1. Class instance: LifeCycleTest@17d88132 In @AfterEach. Class instance: LifeCycleTest@17d88132 Ryuk removed container and associated volume(s): myRepo/myImg In Constructor. Class instance: LifeCycleTest@42d236fb Container myRepo/myImg is starting: 20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1 In @BeforeEach. Class instance: LifeCycleTest@42d236fb, Container id: 20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1 In @Test 2. Class instance: LifeCycleTest@42d236fb No testcontainers action in @Test Test 2 Test 1
  • 43. @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } In @BeforeAll. Static method. In Constructor. Class instance: LifeCycleTest@17d88132 Found Docker environment with local Unix socket (unix:///var/run/docker.sock) Connected to docker Pulling docker image: testcontainers/ryuk Ryuk started - will monitor and terminate Testcontainers containers on JVM exit Checking the system... ✔ Docker server version should be at least 1.6.0 ✔ Docker environment should have more than 2GB free disk space Pulling docker image: myRepo/myImg Container myRepo/myImg is starting: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @Test 1. Class instance: LifeCycleTest@17d88132 In @AfterEach. Class instance: LifeCycleTest@17d88132 Ryuk removed container and associated volume(s): myRepo/myImg In Constructor. Class instance: LifeCycleTest@42d236fb Container myRepo/myImg is starting: 20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1 In @BeforeEach. Class instance: LifeCycleTest@42d236fb, Container id: 20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1 In @Test 2. Class instance: LifeCycleTest@42d236fb In @AfterEach. Class instance: LifeCycleTest@42d236fb Ryuk removed container and associated volume(s): myRepo/myImg In @AfterAll. Static method. After Test 2 “AfterEach”, Ryuk cleans up container Test 2 Test 1
  • 44. @Testcontainers @Slf4j public class LifeCycleTest { @Container GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } In @BeforeAll. Static method. In Constructor. Class instance: LifeCycleTest@17d88132 Found Docker environment with local Unix socket (unix:///var/run/docker.sock) Connected to docker Pulling docker image: testcontainers/ryuk Ryuk started - will monitor and terminate Testcontainers containers on JVM exit Checking the system... ✔ Docker server version should be at least 1.6.0 ✔ Docker environment should have more than 2GB free disk space Pulling docker image: myRepo/myImg Container myRepo/myImg is starting: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @BeforeEach. Class instance: LifeCycleTest@17d88132, Container id: b1c63a2738a6131ac06dd90bc334e621099b8a9d0092cfbc8899954495bd57c5 In @Test 1. Class instance: LifeCycleTest@17d88132 In @AfterEach. Class instance: LifeCycleTest@17d88132 Ryuk removed container and associated volume(s): myRepo/myImg In Constructor. Class instance: LifeCycleTest@42d236fb Container myRepo/myImg is starting: 20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1 In @BeforeEach. Class instance: LifeCycleTest@42d236fb, Container id: 20e4227f6d5366c7f6ccb2ebf09eb5666bb75d20a4c307c6026870dc0fc0d3a1 In @Test 2. Class instance: LifeCycleTest@42d236fb In @AfterEach. Class instance: LifeCycleTest@42d236fb Ryuk removed container and associated volume(s): myRepo/myImg In @AfterAll. Static method. No testcontainers default action in @AfterAll Test 2 Test 1
  • 45. @Testcontainers @Slf4j public class LifeCycleTest { @Container static GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } }
  • 46. @Testcontainers @Slf4j public class LifeCycleTest { @Container static GenericContainer container = new GenericContainer(DockerImageName.parse("myRepo/myImg")); public LifeCycleTest() { log.info("In Constructor. Class instance: ", this); } @BeforeAll public static void beforeAllMethod() { log.info("In @BeforeAll. Static method."); } @BeforeEach public void beforeEachMethod() { log.info("In @BeforeEach. Class instance: " + this + ", Container id: ", container.getContainerId()); } @Test public void test1() { log.info("In @Test 1. Class instance: ", this); } @Test public void test2() { log.info("In @Test 2. Class instance: ", this); } @AfterEach public void afterEachMethod() { log.info("In @AfterEach. Class instance: ", this); } @AfterAll public static void afterAllMethod() { log.info("In @AfterAll. Static method."); } } Found Docker environment with local Unix socket (unix:///var/run/docker.sock) Connected to docker Ryuk started - will monitor and terminate Testcontainers containers on JVM exit Checking the system... ✔ Docker server version should be at least 1.6.0 ✔ Docker environment should have more than 2GB free disk space Container myRepo/myImg is starting: 8d8ff20a9f25dd8b0d4cd025406bdebfa9dcf5ab637ef53b5a815d97bc739b5a In @BeforeAll. Static method. In Constructor. Class instance: LifeCycleTest@63a5d002 In @BeforeEach. Class instance: LifeCycleTest@63a5d002, Container id: 8d8ff20a9f25dd8b0d4cd025406bdebfa9dcf5ab637ef53b5a815d97bc739b5a In @Test 1. Class instance: LifeCycleTest@63a5d002 In @AfterEach. Class instance: LifeCycleTest@63a5d002 In Constructor. Class instance: LifeCycleTest@60e949e1 In @BeforeEach. Class instance: LifeCycleTest@60e949e1, Container id: 8d8ff20a9f25dd8b0d4cd025406bdebfa9dcf5ab637ef53b5a815d97bc739b5a In @Test 2. Class instance: LifeCycleTest@60e949e1 In @AfterEach. Class instance: LifeCycleTest@60e949e1 In @AfterAll. Static method. Ryuk removed container and associated volume(s): myRepo/myImg Container is reused across tests Test 2 Test 1
  • 47. Spring Boot ❤ Testcontainers https://github.com/danvega/reading-list
  • 48. Q&A