SlideShare a Scribd company logo
1 of 75
Download to read offline
Integration tests:
use the containers, Luke!
Roberto “Frank” Franchini
@robfrankie
whoami(1)
https://www.linkedin.com/in/robfrank/
Former CTO of Arcade Analytics
Joined Activiti team in Alfresco
More use cases!
Arcade Analytics
Same output from different data-sources
One new connector per month
New features every week for every connector
Tests: features x connectors
Test Feature B
Test Feature A
Test Feature C
Test Feature D
Deploy without
How to avoid fear?
Integration tests
Activiti Cloud
Activiti Cloud is the first Cloud Native BPM framework built to
provide a scalable and transparent solution for BPM
implementations in cloud environments.
Each microservice has its own integration testing suite that
needs RabbiMQ and KeyCloack to be started before
Every morning a developer wakes up and starts containers
docker run -it -p 5672:5672 -p 15672:15672 --rm rabbitmq:management
docker run -it --rm -p 8180:8180 activiti/activiti-keycloak
Then run tests in the IDE
(Poor developer experience)
Don’t start containers manually anymore
Integration testing is hard
Image credits https://magnasoma.com
Monolith era
Microservices
Unit tests
Integration tests
UI
Tests
Slower
Faster
More
integration
More
isolation
Testcontainers is a Java library that supports JUnit tests,
providing lightweight, throwaway instances of common
databases, Selenium web browsers, or anything else that can
run in a Docker container.
Prerequisites
Ports for GO, .NET, Rust, Js
Main features
Temporary database containers: specialized PostgreSQL,
MySQL, MsSQL Server, MariaDB, Oracle XE, Virtuoso
RDBMS containers
@Container
public static PostgreSQLContainer container = new PostgreSQLContainer();
@Container
public static MySQLContainer container = new MySQLContainer();
@Container
public static OracleContainer container = new OracleContainer();
Others containers: neo4j, couchbase, toxy-proxy, kafka, redis,
influxDB, elasticSearch, rabbitMQ
Others containers
@Container
public static Neo4jContainer container = new Neo4jContainer();
@Container
public static InfluxDBContainer container = new InfluxDBContainer();
@Container
public static KafkaContainer container = new KafkaContainer();
@Container
public static RabbitMQContainer container = new RabbitMQContainer();
Webdriver containers: run a Dockerized Chrome or Firefox
browser ready for Selenium/Webdriver operations - complete
with automatic video recording
Selenium
private val chrome: BrowserWebDriverContainer<Nothing> = BrowserWebDriverContainer<Nothing>()
.apply {
withDesiredCapabilities(DesiredCapabilities.chrome())
withRecordingMode(RECORD_ALL, File("target"))
start()
}
Generic containers: run any Docker container as a test
dependency
Generic container, image based
@Container
public static GenericContainer container = new GenericContainer("orientdb:3.0.23")
.withExposedPorts(2424, 2480)
.withEnv("ORIENTDB_ROOT_PASSWORD", "rootpassword")
.waitingFor(Wait.forListeningPort());
ROM debian:stretch-slim
LABEL maintainer="NGINX Docker Maintainers
<docker-maint@nginx.com>"
ENV NGINX_VERSION 1.15.5-1~stretch
ENV NJS_VERSION 1.15.5.0.2.4-1~stretch
RUN set -x 
&& apt-get update 
&& apt-get install --no-install-recommends
--no-install-suggests -y gnupg1 apt-transport-https
ca-certificates 
&& 
NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9B
F62; 
found=''; 
for server in 
ha.pool.sks-keyservers.net 
hkp://keyserver.ubuntu.com:80 
hkp://p80.pool.sks-keyservers.net:80 
version: '2'
services:
elasticsearch:
build:
context: elasticsearch/
args:
ELK_VERSION: $ELK_VERSION
volumes:
-
./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch
.yml:ro
ports:
- "9200:9200"
- "9300:9300"
environment:
ES_JAVA_OPTS: "-Xmx256m -Xms256m"
networks:
- elk
logstash:
build:
context: logstash/
args:
ELK_VERSION: $ELK_VERSION
volumes:
- ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro
- ./logstash/pipeline:/usr/share/logstash/pipeline:ro
ports:
- "5000:5000"
- "9600:9600"
environment:
LS_JAVA_OPTS: "-Xmx256m -Xms256m"
networks:
- elk
depends_on:
- elasticsearch
kibana:
build:
Use a compose
Start from a Dockerfile
Generic container from Dockerfile
private val container: GenericContainer<Nothing> = GenericContainer<Nothing>(
ImageFromDockerfile("robfrank/ngnix")
.withFileFromPath("Dockerfile", Paths.get("./src/main/docker/nginx/Dockerfile"))
).apply {
withExposedPorts(80)
waitingFor(Wait.forListeningPort())
start()
followOutput(Slf4jLogConsumer(log))
}
Whatever is containerized by your team(s)
DB’s containers? Isn’t
enough?
H2 is fast, BUT doesn’t emulate specific features
Testcontainers is slower*, BUT gives 100% db compatibility
*not so slower
Use in your CI env
Jenkins
DOOD: Docker outside of Docker
DIND: Docker inside of Docker
DOOD: Dockerfile
FROM jenkins/jenkins:lts
USER root
RUN apt-get update 
&& apt-get install -y apt-transport-https ca-certificates curl gnupg2 software-properties-common 
&& curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg 
| apt-key add - 
&& add-apt-repository 
"deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") 
$(lsb_release -cs) 
stable" 
&& apt-get update 
&& apt-get install -y docker-ce 
&& apt-get clean 
&& rm -rf /var/lib/apt/lists/*
RUN usermod -aG docker jenkins
USER jenkins
version: '2'
services:
jenkins:
image: robfrank/jenkins:latest
ports:
- 8080:8080
- 50000:50000
privileged: false
volumes:
- ~/volumes/jenkins_home:/var/jenkins_home
- /usr/bin/docker:/usr/bin/docker
- /var/run/docker.sock:/var/run/docker.sock
- /usr/local/bin/docker-compose:/usr/local/bin/docker-compose
/usr/bin/docker
/usr/bin/docker
Travis: declare the service docker
language: java
service: docker
notifications:
email:
- builder@mycompany.com
before_install:
- docker version
- docker info
- cd ./src/main/docker/orientdb && ./build.sh && cd -
- cd ./src/main/docker/postgresql-dvdrental && ./build.sh && cd -
jdk:
- openjdk8
- openjdk12
Github Actions: just works
Scenarios
Test over different versions of a single database with
parametric test
Test a feature over multiple databases
Test your app against (or supported by) a complex env:
queue, kv-store, log aggregator, search engine
Use a compose file if necessary
Let’s code!
PostgreSQL container
@Container
public static PostgreSQLContainer container = new PostgreSQLContainer();
@Test
public void shouldTestSimpleQuery() throws SQLException {
Connection conn = DriverManager.getConnection(container.getJdbcUrl(),
container.getUsername(), container.getPassword());
Statement stmt = conn.createStatement();
stmt.execute("SELECT 1");
ResultSet resultSet = stmt.getResultSet();
resultSet.next();
assertThat(resultSet.getInt(1)).isEqualTo(1);
}
Jdbc url and init method
@Test
public void shouldSelectFromBar() throws SQLException {
String jdbcUrl =
"jdbc:tc:postgresql:9.6.8://hostname/databasename?&TC_INITFUNCTION=io.github.robfrank.testc
ontainers.JavaJdbcUrlTest::sampleInitFunction";
Connection conn = DriverManager.getConnection(jdbcUrl);
Statement stmt = conn.createStatement();
stmt.execute("SELECT * FROM bar");
ResultSet resultSet = stmt.getResultSet();
resultSet.next();
assertThat(resultSet.getString("foo")).isEqualTo("hello world");
}
Jdbc url and init method
public static void sampleInitFunction(Connection connection) throws SQLException {
connection.createStatement().execute("CREATE TABLE bar (n" +
" foo VARCHAR(255)n" +
");");
connection.createStatement().execute("INSERT INTO bar (foo) VALUES ('hello world');");
connection.createStatement().execute("CREATE TABLE my_counter (n" +
" n INTn" +
");");
}
Jdbc url script
@Test
public void shouldSelectFromBar() throws SQLException {
String jdbcUrl =
"jdbc:tc:postgresql:9.6.8://hostname/databasename?&TC_INITSCRIPT=initdb.sql";
Connection conn = DriverManager.getConnection(jdbcUrl);
Statement stmt = conn.createStatement();
stmt.execute("SELECT * FROM bar");
ResultSet resultSet = stmt.getResultSet();
resultSet.next();
assertThat(resultSet.getString("foo")).isEqualTo("hello world");
}
Generic container, image based
@Container
public static GenericContainer container = new GenericContainer("orientdb:3.0.23")
.withExposedPorts(2424, 2480)
.withEnv("ORIENTDB_ROOT_PASSWORD", "rootpassword")
.waitingFor(Wait.forListeningPort());
Generic container, image based
@Test
internal fun `should select beers vertexes`() {
OrientDB("remote:${container.containerIpAddress}:${container.firstMappedPort}", OrientDBConfig.defaultConfig()).use {
orientDB ->
orientDB.open("openbeer", "admin", "admin").use { db ->
db.query("select from Beer limit 10").use { resultSet ->
resultSet.asSequence()
.toList().apply {
assertThat(this).hasSize(10)
}.map { record ->
assertThat(record.isVertex).isTrue()
assertThat(record.hasProperty("name")).isTrue()
assertThat(record.hasProperty("descript")).isTrue()
record.vertex.get()
}.forEach { vertex: OVertex ->
assertThat(vertex.getEdges(ODirection.OUT)).isNotEmpty
}
}
}
}
Recap
Add to your project
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.12.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>MODULE_NAME</artifactId>
<version>1.12.0</version>
<scope>test</scope>
</dependency>
Use in test
@Container
val container = PostgreSQLContainer<Nothing>()
@Test fun `should perform simple query`() {
val conn = DriverManager.getConnection(container.jdbcUrl,
container.username,
container.password)
val stmt = conn.createStatement()
stmt.execute("SELECT 1")
val resultSet = stmt.resultSet
resultSet.next()
assertThat(resultSet.getInt(1)).isEqualTo(1)
}
https://github.com/robfrank/testcontainers-examples
ArcadeAnalytics connectors: https://github.com/arcadeAnalytics/arcade-connectors/
Kotlin and Java
Single container for multiple test classes
Neo4j, Postgres, Mysql, OrientDB, JanusGraph test and custom images
Alfresco Activiti: https://github.com/Activiti/activiti-cloud-query-service
Use of Testcontainers instead of maven plugin for lifecycle
Other examples
Thank you!

More Related Content

What's hot

What's hot (20)

Cncf checkov and bridgecrew
Cncf checkov and bridgecrewCncf checkov and bridgecrew
Cncf checkov and bridgecrew
 
Travis CI
Travis CITravis CI
Travis CI
 
Introduction to Integration Testing With Cypress
Introduction to Integration Testing With CypressIntroduction to Integration Testing With Cypress
Introduction to Integration Testing With Cypress
 
Kubernetes #2 monitoring
Kubernetes #2   monitoring Kubernetes #2   monitoring
Kubernetes #2 monitoring
 
Explore your prometheus data in grafana - Promcon 2018
Explore your prometheus data in grafana - Promcon 2018Explore your prometheus data in grafana - Promcon 2018
Explore your prometheus data in grafana - Promcon 2018
 
Mule Runtime のアーキテクチャコンセプト紹介
Mule Runtime のアーキテクチャコンセプト紹介Mule Runtime のアーキテクチャコンセプト紹介
Mule Runtime のアーキテクチャコンセプト紹介
 
Cpp unit
Cpp unit Cpp unit
Cpp unit
 
Kafka slideshare
Kafka   slideshareKafka   slideshare
Kafka slideshare
 
Introduction to Testcontainers
Introduction to TestcontainersIntroduction to Testcontainers
Introduction to Testcontainers
 
クラウド環境でのセキュリティ監査自動化【DeNA TechCon 2020 ライブ配信】
クラウド環境でのセキュリティ監査自動化【DeNA TechCon 2020 ライブ配信】クラウド環境でのセキュリティ監査自動化【DeNA TechCon 2020 ライブ配信】
クラウド環境でのセキュリティ監査自動化【DeNA TechCon 2020 ライブ配信】
 
Optimizing {Java} Application Performance on Kubernetes
Optimizing {Java} Application Performance on KubernetesOptimizing {Java} Application Performance on Kubernetes
Optimizing {Java} Application Performance on Kubernetes
 
Service Mesh - Why? How? What?
Service Mesh - Why? How? What?Service Mesh - Why? How? What?
Service Mesh - Why? How? What?
 
[2018] NHN 모니터링의 현재와 미래 for 인프라 엔지니어
[2018] NHN 모니터링의 현재와 미래 for 인프라 엔지니어[2018] NHN 모니터링의 현재와 미래 for 인프라 엔지니어
[2018] NHN 모니터링의 현재와 미래 for 인프라 엔지니어
 
Choose your own adventure Chaos Engineering - QCon NYC 2017
Choose your own adventure Chaos Engineering - QCon NYC 2017 Choose your own adventure Chaos Engineering - QCon NYC 2017
Choose your own adventure Chaos Engineering - QCon NYC 2017
 
쿠버네티스를 이용한 기능 브랜치별 테스트 서버 만들기 (GitOps CI/CD)
쿠버네티스를 이용한 기능 브랜치별 테스트 서버 만들기 (GitOps CI/CD)쿠버네티스를 이용한 기능 브랜치별 테스트 서버 만들기 (GitOps CI/CD)
쿠버네티스를 이용한 기능 브랜치별 테스트 서버 만들기 (GitOps CI/CD)
 
How we can do Multi-Tenancy on Kubernetes
How we can do Multi-Tenancy on KubernetesHow we can do Multi-Tenancy on Kubernetes
How we can do Multi-Tenancy on Kubernetes
 
Devops Mindset Essentials
Devops Mindset EssentialsDevops Mindset Essentials
Devops Mindset Essentials
 
Introduction to DevSecOps
Introduction to DevSecOpsIntroduction to DevSecOps
Introduction to DevSecOps
 
Junit
JunitJunit
Junit
 
Introduction to Microservices
Introduction to MicroservicesIntroduction to Microservices
Introduction to Microservices
 

Similar to Integration tests: use the containers, Luke!

Similar to Integration tests: use the containers, Luke! (20)

RichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile DevicesRichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile Devices
 
Release with confidence
Release with confidenceRelease with confidence
Release with confidence
 
OWASP ZAP Workshop for QA Testers
OWASP ZAP Workshop for QA TestersOWASP ZAP Workshop for QA Testers
OWASP ZAP Workshop for QA Testers
 
AWS December 2015 Webinar Series - Continuous Delivery to Amazon EC2 Containe...
AWS December 2015 Webinar Series - Continuous Delivery to Amazon EC2 Containe...AWS December 2015 Webinar Series - Continuous Delivery to Amazon EC2 Containe...
AWS December 2015 Webinar Series - Continuous Delivery to Amazon EC2 Containe...
 
Continuous Delivery with Docker and Amazon ECS
Continuous Delivery with Docker and Amazon ECSContinuous Delivery with Docker and Amazon ECS
Continuous Delivery with Docker and Amazon ECS
 
Test Automation for NoSQL Databases
Test Automation for NoSQL DatabasesTest Automation for NoSQL Databases
Test Automation for NoSQL Databases
 
DCSF 19 Building Your Development Pipeline
DCSF 19 Building Your Development Pipeline  DCSF 19 Building Your Development Pipeline
DCSF 19 Building Your Development Pipeline
 
Docker & ECS: Secure Nearline Execution
Docker & ECS: Secure Nearline ExecutionDocker & ECS: Secure Nearline Execution
Docker & ECS: Secure Nearline Execution
 
Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...
Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...
Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...
 
Using Kubernetes for Continuous Integration and Continuous Delivery
Using Kubernetes for Continuous Integration and Continuous DeliveryUsing Kubernetes for Continuous Integration and Continuous Delivery
Using Kubernetes for Continuous Integration and Continuous Delivery
 
Using Kubernetes for Continuous Integration and Continuous Delivery. Java2days
Using Kubernetes for Continuous Integration and Continuous Delivery. Java2daysUsing Kubernetes for Continuous Integration and Continuous Delivery. Java2days
Using Kubernetes for Continuous Integration and Continuous Delivery. Java2days
 
Deploying windows containers with kubernetes
Deploying windows containers with kubernetesDeploying windows containers with kubernetes
Deploying windows containers with kubernetes
 
In the Brain of Hans Dockter: Gradle
In the Brain of Hans Dockter: GradleIn the Brain of Hans Dockter: Gradle
In the Brain of Hans Dockter: Gradle
 
Javascript tdd byandreapaciolla
Javascript tdd byandreapaciollaJavascript tdd byandreapaciolla
Javascript tdd byandreapaciolla
 
GeeCON 2017 - TestContainers. Integration testing without the hassle
GeeCON 2017 - TestContainers. Integration testing without the hassleGeeCON 2017 - TestContainers. Integration testing without the hassle
GeeCON 2017 - TestContainers. Integration testing without the hassle
 
Continuous Integration With Jenkins Docker SQL Server
Continuous Integration With Jenkins Docker SQL ServerContinuous Integration With Jenkins Docker SQL Server
Continuous Integration With Jenkins Docker SQL Server
 
(Declarative) Jenkins Pipelines
(Declarative) Jenkins Pipelines(Declarative) Jenkins Pipelines
(Declarative) Jenkins Pipelines
 
Develop with docker 2014 aug
Develop with docker 2014 augDevelop with docker 2014 aug
Develop with docker 2014 aug
 
Docker presentasjon java bin
Docker presentasjon java binDocker presentasjon java bin
Docker presentasjon java bin
 
Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3
 

More from Roberto Franchini

More from Roberto Franchini (8)

OrientDB - The 2nd generation of (multi-model) NoSQL
OrientDB - The 2nd generation of  (multi-model) NoSQLOrientDB - The 2nd generation of  (multi-model) NoSQL
OrientDB - The 2nd generation of (multi-model) NoSQL
 
Where are yours vertexes and what are they talking about?
Where are yours vertexes and what are they talking about?Where are yours vertexes and what are they talking about?
Where are yours vertexes and what are they talking about?
 
What the hell is your software doing at runtime?
What the hell is your software doing at runtime?What the hell is your software doing at runtime?
What the hell is your software doing at runtime?
 
Java application monitoring with Dropwizard Metrics and graphite
Java application monitoring with Dropwizard Metrics and graphite Java application monitoring with Dropwizard Metrics and graphite
Java application monitoring with Dropwizard Metrics and graphite
 
Codemotion Rome 2015. GlusterFS
Codemotion Rome 2015. GlusterFSCodemotion Rome 2015. GlusterFS
Codemotion Rome 2015. GlusterFS
 
GlusterFs: a scalable file system for today's and tomorrow's big data
GlusterFs: a scalable file system for today's and tomorrow's big dataGlusterFs: a scalable file system for today's and tomorrow's big data
GlusterFs: a scalable file system for today's and tomorrow's big data
 
Redis for duplicate detection on real time stream
Redis for duplicate detection on real time streamRedis for duplicate detection on real time stream
Redis for duplicate detection on real time stream
 
TDD - una introduzione
TDD -  una introduzioneTDD -  una introduzione
TDD - una introduzione
 

Recently uploaded

Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
masabamasaba
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 

Recently uploaded (20)

call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%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
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
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
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
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
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
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?
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
%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
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT  - Elevating Productivity in Today's Agile EnvironmentHarnessing ChatGPT  - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 

Integration tests: use the containers, Luke!

  • 1. Integration tests: use the containers, Luke! Roberto “Frank” Franchini @robfrankie
  • 3. Former CTO of Arcade Analytics Joined Activiti team in Alfresco
  • 6.
  • 7.
  • 8.
  • 9. Same output from different data-sources
  • 10. One new connector per month
  • 11. New features every week for every connector
  • 12. Tests: features x connectors
  • 13. Test Feature B Test Feature A Test Feature C Test Feature D
  • 15. How to avoid fear?
  • 17.
  • 19. Activiti Cloud is the first Cloud Native BPM framework built to provide a scalable and transparent solution for BPM implementations in cloud environments.
  • 20.
  • 21.
  • 22. Each microservice has its own integration testing suite that needs RabbiMQ and KeyCloack to be started before
  • 23. Every morning a developer wakes up and starts containers docker run -it -p 5672:5672 -p 15672:15672 --rm rabbitmq:management docker run -it --rm -p 8180:8180 activiti/activiti-keycloak
  • 24. Then run tests in the IDE (Poor developer experience)
  • 25. Don’t start containers manually anymore
  • 30.
  • 31. Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
  • 33.
  • 34. Ports for GO, .NET, Rust, Js
  • 36. Temporary database containers: specialized PostgreSQL, MySQL, MsSQL Server, MariaDB, Oracle XE, Virtuoso
  • 37. RDBMS containers @Container public static PostgreSQLContainer container = new PostgreSQLContainer(); @Container public static MySQLContainer container = new MySQLContainer(); @Container public static OracleContainer container = new OracleContainer();
  • 38. Others containers: neo4j, couchbase, toxy-proxy, kafka, redis, influxDB, elasticSearch, rabbitMQ
  • 39. Others containers @Container public static Neo4jContainer container = new Neo4jContainer(); @Container public static InfluxDBContainer container = new InfluxDBContainer(); @Container public static KafkaContainer container = new KafkaContainer(); @Container public static RabbitMQContainer container = new RabbitMQContainer();
  • 40. Webdriver containers: run a Dockerized Chrome or Firefox browser ready for Selenium/Webdriver operations - complete with automatic video recording
  • 41. Selenium private val chrome: BrowserWebDriverContainer<Nothing> = BrowserWebDriverContainer<Nothing>() .apply { withDesiredCapabilities(DesiredCapabilities.chrome()) withRecordingMode(RECORD_ALL, File("target")) start() }
  • 42. Generic containers: run any Docker container as a test dependency
  • 43. Generic container, image based @Container public static GenericContainer container = new GenericContainer("orientdb:3.0.23") .withExposedPorts(2424, 2480) .withEnv("ORIENTDB_ROOT_PASSWORD", "rootpassword") .waitingFor(Wait.forListeningPort());
  • 44. ROM debian:stretch-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" ENV NGINX_VERSION 1.15.5-1~stretch ENV NJS_VERSION 1.15.5.0.2.4-1~stretch RUN set -x && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 apt-transport-https ca-certificates && NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9B F62; found=''; for server in ha.pool.sks-keyservers.net hkp://keyserver.ubuntu.com:80 hkp://p80.pool.sks-keyservers.net:80 version: '2' services: elasticsearch: build: context: elasticsearch/ args: ELK_VERSION: $ELK_VERSION volumes: - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch .yml:ro ports: - "9200:9200" - "9300:9300" environment: ES_JAVA_OPTS: "-Xmx256m -Xms256m" networks: - elk logstash: build: context: logstash/ args: ELK_VERSION: $ELK_VERSION volumes: - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro - ./logstash/pipeline:/usr/share/logstash/pipeline:ro ports: - "5000:5000" - "9600:9600" environment: LS_JAVA_OPTS: "-Xmx256m -Xms256m" networks: - elk depends_on: - elasticsearch kibana: build: Use a compose Start from a Dockerfile
  • 45. Generic container from Dockerfile private val container: GenericContainer<Nothing> = GenericContainer<Nothing>( ImageFromDockerfile("robfrank/ngnix") .withFileFromPath("Dockerfile", Paths.get("./src/main/docker/nginx/Dockerfile")) ).apply { withExposedPorts(80) waitingFor(Wait.forListeningPort()) start() followOutput(Slf4jLogConsumer(log)) }
  • 46. Whatever is containerized by your team(s)
  • 48. H2 is fast, BUT doesn’t emulate specific features
  • 49. Testcontainers is slower*, BUT gives 100% db compatibility *not so slower
  • 50. Use in your CI env
  • 51. Jenkins DOOD: Docker outside of Docker DIND: Docker inside of Docker
  • 52. DOOD: Dockerfile FROM jenkins/jenkins:lts USER root RUN apt-get update && apt-get install -y apt-transport-https ca-certificates curl gnupg2 software-properties-common && curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | apt-key add - && add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") $(lsb_release -cs) stable" && apt-get update && apt-get install -y docker-ce && apt-get clean && rm -rf /var/lib/apt/lists/* RUN usermod -aG docker jenkins USER jenkins
  • 53. version: '2' services: jenkins: image: robfrank/jenkins:latest ports: - 8080:8080 - 50000:50000 privileged: false volumes: - ~/volumes/jenkins_home:/var/jenkins_home - /usr/bin/docker:/usr/bin/docker - /var/run/docker.sock:/var/run/docker.sock - /usr/local/bin/docker-compose:/usr/local/bin/docker-compose
  • 55. Travis: declare the service docker
  • 56. language: java service: docker notifications: email: - builder@mycompany.com before_install: - docker version - docker info - cd ./src/main/docker/orientdb && ./build.sh && cd - - cd ./src/main/docker/postgresql-dvdrental && ./build.sh && cd - jdk: - openjdk8 - openjdk12
  • 59. Test over different versions of a single database with parametric test
  • 60. Test a feature over multiple databases
  • 61. Test your app against (or supported by) a complex env: queue, kv-store, log aggregator, search engine
  • 62. Use a compose file if necessary
  • 64. PostgreSQL container @Container public static PostgreSQLContainer container = new PostgreSQLContainer(); @Test public void shouldTestSimpleQuery() throws SQLException { Connection conn = DriverManager.getConnection(container.getJdbcUrl(), container.getUsername(), container.getPassword()); Statement stmt = conn.createStatement(); stmt.execute("SELECT 1"); ResultSet resultSet = stmt.getResultSet(); resultSet.next(); assertThat(resultSet.getInt(1)).isEqualTo(1); }
  • 65. Jdbc url and init method @Test public void shouldSelectFromBar() throws SQLException { String jdbcUrl = "jdbc:tc:postgresql:9.6.8://hostname/databasename?&TC_INITFUNCTION=io.github.robfrank.testc ontainers.JavaJdbcUrlTest::sampleInitFunction"; Connection conn = DriverManager.getConnection(jdbcUrl); Statement stmt = conn.createStatement(); stmt.execute("SELECT * FROM bar"); ResultSet resultSet = stmt.getResultSet(); resultSet.next(); assertThat(resultSet.getString("foo")).isEqualTo("hello world"); }
  • 66. Jdbc url and init method public static void sampleInitFunction(Connection connection) throws SQLException { connection.createStatement().execute("CREATE TABLE bar (n" + " foo VARCHAR(255)n" + ");"); connection.createStatement().execute("INSERT INTO bar (foo) VALUES ('hello world');"); connection.createStatement().execute("CREATE TABLE my_counter (n" + " n INTn" + ");"); }
  • 67. Jdbc url script @Test public void shouldSelectFromBar() throws SQLException { String jdbcUrl = "jdbc:tc:postgresql:9.6.8://hostname/databasename?&TC_INITSCRIPT=initdb.sql"; Connection conn = DriverManager.getConnection(jdbcUrl); Statement stmt = conn.createStatement(); stmt.execute("SELECT * FROM bar"); ResultSet resultSet = stmt.getResultSet(); resultSet.next(); assertThat(resultSet.getString("foo")).isEqualTo("hello world"); }
  • 68. Generic container, image based @Container public static GenericContainer container = new GenericContainer("orientdb:3.0.23") .withExposedPorts(2424, 2480) .withEnv("ORIENTDB_ROOT_PASSWORD", "rootpassword") .waitingFor(Wait.forListeningPort());
  • 69. Generic container, image based @Test internal fun `should select beers vertexes`() { OrientDB("remote:${container.containerIpAddress}:${container.firstMappedPort}", OrientDBConfig.defaultConfig()).use { orientDB -> orientDB.open("openbeer", "admin", "admin").use { db -> db.query("select from Beer limit 10").use { resultSet -> resultSet.asSequence() .toList().apply { assertThat(this).hasSize(10) }.map { record -> assertThat(record.isVertex).isTrue() assertThat(record.hasProperty("name")).isTrue() assertThat(record.hasProperty("descript")).isTrue() record.vertex.get() }.forEach { vertex: OVertex -> assertThat(vertex.getEdges(ODirection.OUT)).isNotEmpty } } } }
  • 70. Recap
  • 71. Add to your project <dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers</artifactId> <version>1.12.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>MODULE_NAME</artifactId> <version>1.12.0</version> <scope>test</scope> </dependency>
  • 72. Use in test @Container val container = PostgreSQLContainer<Nothing>() @Test fun `should perform simple query`() { val conn = DriverManager.getConnection(container.jdbcUrl, container.username, container.password) val stmt = conn.createStatement() stmt.execute("SELECT 1") val resultSet = stmt.resultSet resultSet.next() assertThat(resultSet.getInt(1)).isEqualTo(1) }
  • 74. ArcadeAnalytics connectors: https://github.com/arcadeAnalytics/arcade-connectors/ Kotlin and Java Single container for multiple test classes Neo4j, Postgres, Mysql, OrientDB, JanusGraph test and custom images Alfresco Activiti: https://github.com/Activiti/activiti-cloud-query-service Use of Testcontainers instead of maven plugin for lifecycle Other examples