Slide 1

Slide 1 text

Testcontainers Integration testing without the hassle Sergei @bsideup Egorov

Slide 2

Slide 2 text

About me • Testcontainers co-maintainer • Staff Engineer at Pivotal’s Spring R&D, working on Project Reactor ⚛ • Berlin Spring User Group co-organizer • Developer tools geek @bsideup

Slide 3

Slide 3 text

Integration testing?

Slide 4

Slide 4 text

@bsideup

Slide 5

Slide 5 text

@bsideup

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

So…
 Integration testing.

Slide 13

Slide 13 text

Verify how your software product will behave in real- world conditions

Slide 14

Slide 14 text

Isolated from other system components to avoid false negatives

Slide 15

Slide 15 text

Real: databases, file systems, network interfaces, …

Slide 16

Slide 16 text

Grey box testing - we know some inner details, but mostly use public APIs

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Unit testing • Simulation tests are green, yay! • Everything is mocked • DB is written by others, why should I test it? @bsideup

Slide 19

Slide 19 text

Integration testing https://commons.wikimedia.org/wiki/File:Cd4007.jpg • Jeez, how did it passed the Unit testing? • Is it a smoke? @#$%! YES IT IS! • Who knew that 100w soldering gun was a bit too powerful for it? @bsideup

Slide 20

Slide 20 text

System testing https://commons.wikimedia.org/wiki/File:UART_8250_Microchip.jpg • Takes a lot of time to solder • “Oh no, the power bus is too far away from my microchip!” • Interference between the components @bsideup

Slide 21

Slide 21 text

Production @bsideup

Slide 22

Slide 22 text

Integration testing Real-world, but isolated testing Spot the issues before the real environment Can be run during the development You have to start real databases Should be cross-platform Slower than Unit testing Pros Cons @bsideup

Slide 23

Slide 23 text

Integration testing transformation @bsideup

Slide 24

Slide 24 text

Mocking Integration testing transformation @bsideup

Slide 25

Slide 25 text

Mocking Local DBs Integration testing transformation @bsideup

Slide 26

Slide 26 text

Mocking Local DBs VMs
 (Vagrant) Integration testing transformation @bsideup

Slide 27

Slide 27 text

Mocking Local DBs VMs
 (Vagrant) Docker Integration testing transformation @bsideup

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

Abstraction layer

Slide 30

Slide 30 text

CI friendly

Slide 31

Slide 31 text

Cross-platform

Slide 32

Slide 32 text

Mocking Local DBs VMs
 (Vagrant) Docker Integration testing transformation @bsideup

Slide 33

Slide 33 text

Mocking Local DBs VMs
 (Vagrant) Docker Fig
 (aka Docker Compose) Integration testing transformation @bsideup

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

But…

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

IDE integration? @bsideup

Slide 40

Slide 40 text

Mocking Local DBs VMs
 (Vagrant) Docker Fig
 (aka Docker Compose) Integration testing transformation @bsideup

Slide 41

Slide 41 text

Mocking Local DBs VMs
 (Vagrant) Docker Fig
 (aka Docker Compose) Docker API Integration testing transformation @bsideup

Slide 42

Slide 42 text

Fighting with Docker environment

Slide 43

Slide 43 text

There is no place like

Slide 44

Slide 44 text

There is no place like … unless there is

Slide 45

Slide 45 text

Can we improve that?

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

Users

Slide 50

Slide 50 text

@bsideup

Slide 51

Slide 51 text

Use case: testing of microservices • REST service • Java, Spring Boot • Redis, Kafka and PostgreSQL • Calls some other micro-services @bsideup

Slide 52

Slide 52 text

@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = Initializer.class) public abstract class AbstractIntegrationTest { @ClassRule public static GenericContainer redis = new GenericContainer("redis:3.0.6") .withExposedPorts(6379); @ClassRule public static MockServerContainer mockServer = new MockServerContainer(); } @bsideup

Slide 53

Slide 53 text

@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = Initializer.class) public abstract class AbstractIntegrationTest { @ClassRule public static GenericContainer redis = new GenericContainer("redis:3.0.6") .withExposedPorts(6379); @ClassRule public static MockServerContainer mockServer = new MockServerContainer(); } Still using all the Spring goodies! @bsideup

Slide 54

Slide 54 text

@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = Initializer.class) public abstract class AbstractIntegrationTest { @ClassRule public static GenericContainer redis = new GenericContainer("redis:3.0.6") .withExposedPorts(6379); @ClassRule public static MockServerContainer mockServer = new MockServerContainer(); } External dependencies @bsideup

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

Demo

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

Questions?

Slide 59

Slide 59 text

@bsideup bsideup

Slide 60

Slide 60 text

https://commons.wikimedia.org/wiki/File:Thats_all_folks.svg