SlideShare a Scribd company logo
TestContainers
Integration testing without the hassle
@antonarhipov
JavaOne 2017 - TestContainers: integration testing without the hassle
Why integration testing?
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
1. # of tests per time unit
1. # of tests per time unit
2. Complex setup
JavaOne 2017 - TestContainers: integration testing without the hassle
1. Reproducible environment
1. Reproducible environment
2. Both for development and CI
1. Reproducible environment
2. Both for development and CI
3. Isolated
1. Reproducible environment
2. Both for development and CI
3. Isolated
4. As real as possible
1. Reproducible environment
2. Both for development and CI
3. Isolated
4. As real as possible
5. Cross-platform
1. Reproducible environment
2. Both for development and CI
3. Isolated
4. As real as possible
5. Cross-platform
6. Easy to set up, use & maintain
JavaOne 2017 - TestContainers: integration testing without the hassle
Docker Compose FTW!
redis:

image: redis

ports:

- "6379:6379"

postgres:

image: postgres

ports:

- "5432:5432"

elasticsearch:

image: elasticsearch:5.0.0

ports:

- "9200:9200"

JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
TestContainers to the rescue!
How does it work?
https://github.com/docker-java/docker-java
Docker environment discovery
Will start docker machine if it’s not started yet
Containers cleanup on JVM shutdown
GenericContainer redis =
new GenericContainer("redis:3.0.6")
.withExposedPorts(6379);
GenericContainer redis =
new GenericContainer("redis:3.0.6")
.withExposedPorts(6379);
PostgreSQLContainer postgreSQLContainer =
new PostgreSQLContainer("postgres:9.6.2")
.withUsername(POSTGRES_USERNAME)
.withPassword(POSTGRES_PASSWORD);
TestContainers
https://github.com/testcontainers/testcontainers-java
Docker Compose? - Yes!
public static DockerComposeContainer env =
new DockerComposeContainer(
new File("src/test/resources/compose-test.yml"))
.withExposedService("redis_1", REDIS_PORT);
Docker Compose? - Yes!
public static DockerComposeContainer env =
new DockerComposeContainer(
new File("src/test/resources/compose-test.yml"))
.withExposedService("redis_1", REDIS_PORT);
String url = env.getServiceHost("redis_1", REDIS_PORT);
Integer port = env.getServicePort("redis_1", REDIS_PORT);
Jedis jedis = new Jedis(url, port);
Microservices!11
REST service
Java, Spring Boot
Redis & PostgreSQL
Calls some other micro-services
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DemoApplication.class,
webEnvironment = WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
public abstract class AbstractIntegrationTest {
@ClassRule
public static PostgreSQLContainer postgreSql = new PostgreSQLContainer();
@ClassRule
public static GenericContainer redis = new GenericContainer("redis:3.0.6")
.withExposedPorts(6379);
@ClassRule
public static MockServerContainer mockServer = new MockServerContainer();
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DemoApplication.class,
webEnvironment = WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
public abstract class AbstractIntegrationTest {
@ClassRule
public static PostgreSQLContainer postgreSql = new PostgreSQLContainer();
@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!
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DemoApplication.class,
webEnvironment = WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
public abstract class AbstractIntegrationTest {
@ClassRule
public static PostgreSQLContainer postgreSql = new PostgreSQLContainer();
@ClassRule
public static GenericContainer redis = new GenericContainer("redis:3.0.6")
.withExposedPorts(6379);
@ClassRule
public static MockServerContainer mockServer = new MockServerContainer();
External
dependencies
JavaOne 2017 - TestContainers: integration testing without the hassle
public class MockServerContainer<SELF extends MockServerContainer<SELF>>
extends GenericContainer<SELF> {
public MockServerContainer() {
super("jamesdbloom/mockserver:latest");
addExposedPorts(8080);
}
private MockServerClient client;
@Override
protected void containerIsStarted(InspectContainerResponse containerInfo) {
super.containerIsStarted(containerInfo);
client = new MockServerClient(getContainerIpAddress(),
getMappedPort(getExposedPorts().get(0)));
}
}
public class MockServerContainer<SELF extends MockServerContainer<SELF>>
extends GenericContainer<SELF> {
public MockServerContainer() {
super("jamesdbloom/mockserver:latest");
addExposedPorts(8080);
}
private MockServerClient client;
@Override
protected void containerIsStarted(InspectContainerResponse containerInfo) {
super.containerIsStarted(containerInfo);
client = new MockServerClient(getContainerIpAddress(),
getMappedPort(getExposedPorts().get(0)));
}
}
MockServerClient client = …
client.when(
HttpRequest.request("/analytics/issues/" +
project.projectId + "/app").withMethod("GET"),
Times.unlimited())
.respond(singleIssueResponse());
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
How to test Java agents?
public static void premain(String args, Instrumentation instrumentation) {
instrumentation.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if ("spark/webserver/JettyHandler".equals(className)) {
try {
ClassPool cp = new ClassPool();
cp.appendClassPath(new LoaderClassPath(loader));
CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer));
CtMethod ctMethod = ct.getDeclaredMethod("doHandle");
ctMethod.insertBefore("{ $4.setHeader("X-My-Super-Header", "header value"); }");
return ct.toBytecode();
} catch (Throwable e) {
e.printStackTrace();
}
}
return classfileBuffer;
}
});
}
public static void premain(String args, Instrumentation instrumentation) {
instrumentation.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if ("spark/webserver/JettyHandler".equals(className)) {
try {
ClassPool cp = new ClassPool();
cp.appendClassPath(new LoaderClassPath(loader));
CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer));
CtMethod ctMethod = ct.getDeclaredMethod("doHandle");
ctMethod.insertBefore("{ $4.setHeader("X-My-Super-Header", "header value"); }");
return ct.toBytecode();
} catch (Throwable e) {
e.printStackTrace();
}
}
return classfileBuffer;
}
});
}
public static void premain(String args, Instrumentation instrumentation) {
instrumentation.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if ("spark/webserver/JettyHandler".equals(className)) {
try {
ClassPool cp = new ClassPool();
cp.appendClassPath(new LoaderClassPath(loader));
CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer));
CtMethod ctMethod = ct.getDeclaredMethod("doHandle");
ctMethod.insertBefore("{ $4.setHeader("X-My-Super-Header", "header value"); }");
return ct.toBytecode();
} catch (Throwable e) {
e.printStackTrace();
}
}
return classfileBuffer;
}
});
}
public class AgentTest {
@ClassRule
public static BasicTestApp app = new BasicTestApp();
@Test
public void testIt() throws Exception {
Response response = app.getClient().getHello();
System.out.println("Got response:n" + response);
assertThat(response.headers().get("X-My-Super-Header"))
.isNotNull()
.hasSize(1)
.containsExactly("header value");
}
}
public class AgentTest {
@ClassRule
public static BasicTestApp app = new BasicTestApp();
@Test
public void testIt() throws Exception {
Response response = app.getClient().getHello();
System.out.println("Got response:n" + response);
assertThat(response.headers().get("X-My-Super-Header"))
.isNotNull()
.hasSize(1)
.containsExactly("header value");
}
}
A custom
container
public class AgentTest {
@ClassRule
public static BasicTestApp app = new BasicTestApp();
@Test
public void testIt() throws Exception {
Response response = app.getClient().getHello();
System.out.println("Got response:n" + response);
assertThat(response.headers().get("X-My-Super-Header"))
.isNotNull()
.hasSize(1)
.containsExactly("header value");
}
}
Verify, if the
new behaviour is
there
https://github.com/bsideup/javaagent-boilerplate
https://www.testcontainers.org
https://twitter.com/testcontainers
https://github.com/testcontainers
https://testcontainers.slack.com
anton@zeroturnaround.com
@antonarhipov
slideshare.net/arhan

More Related Content

PDF
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
PDF
JavaDay Kiev 2017 - Integration testing with TestContainers
PDF
GeeCON Prague 2017 - TestContainers
PDF
Docker In Bank Unrated
PDF
Docker In the Bank
PDF
Testing the Enterprise layers, with Arquillian
DOCX
Manoj Kolhe - Setup GitHub with Jenkins on Amazon Cloud - End-to-end Automation
PDF
Checking Bitcoin
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaDay Kiev 2017 - Integration testing with TestContainers
GeeCON Prague 2017 - TestContainers
Docker In Bank Unrated
Docker In the Bank
Testing the Enterprise layers, with Arquillian
Manoj Kolhe - Setup GitHub with Jenkins on Amazon Cloud - End-to-end Automation
Checking Bitcoin

What's hot (20)

PDF
Everything as a code
PDF
The Ring programming language version 1.8 book - Part 77 of 202
PDF
The Ring programming language version 1.7 book - Part 75 of 196
PDF
Resilence patterns kr
PPTX
Going native with less coupling: Dependency Injection in C++
PPTX
Capistrano与jenkins(hudson)在java web项目中的实践
KEY
VCLをTDDで書いてデプロイする
PDF
App container rkt
PDF
Testing in android
PDF
232 deview2013 oss를활용한분산아키텍처구현
PDF
Docker and Your Path to a Better Staging Environment - webinar by Gil Tayar
PDF
時代在變 Docker 要會:台北 Docker 一日入門篇
PDF
高レイテンシwebサーバのGKE構築と beta機能アレコレのハナシ
PDF
Testing Java Code Effectively
PPTX
Workshop MSF4J - Getting Started with Microservices and Java
ODP
Nodejs Intro - Part2 Introduction to Web Applications
PDF
Vagrant plugin development intro
PPT
Nodejs Intro Part One
PDF
Spocktacular testing
PDF
Discovering Volume Plugins with Applications using Docker Toolbox and VirtualBox
Everything as a code
The Ring programming language version 1.8 book - Part 77 of 202
The Ring programming language version 1.7 book - Part 75 of 196
Resilence patterns kr
Going native with less coupling: Dependency Injection in C++
Capistrano与jenkins(hudson)在java web项目中的实践
VCLをTDDで書いてデプロイする
App container rkt
Testing in android
232 deview2013 oss를활용한분산아키텍처구현
Docker and Your Path to a Better Staging Environment - webinar by Gil Tayar
時代在變 Docker 要會:台北 Docker 一日入門篇
高レイテンシwebサーバのGKE構築と beta機能アレコレのハナシ
Testing Java Code Effectively
Workshop MSF4J - Getting Started with Microservices and Java
Nodejs Intro - Part2 Introduction to Web Applications
Vagrant plugin development intro
Nodejs Intro Part One
Spocktacular testing
Discovering Volume Plugins with Applications using Docker Toolbox and VirtualBox
Ad

Similar to JavaOne 2017 - TestContainers: integration testing without the hassle (20)

PDF
GeeCON 2017 - TestContainers. Integration testing without the hassle
PDF
Level Up Your Integration Testing With Testcontainers
PPTX
Simplifying Integration Testing in a Containerized World
PDF
Integration tests: use the containers, Luke!
PDF
Testcontainers - Geekout EE 2017 presentation
PPTX
Testcontainers: Reliable, Isolated, and Reproducible Testing for External Dep...
PDF
Prod-Like Integration Testing for Distributed Containerized Applications
PPTX
JBCN_Testing_With_Containers
PDF
JUnit5 and TestContainers
PPTX
JLove - Replicating production on your laptop using the magic of containers
PDF
Take Control of your Integration Testing with TestContainers
PPTX
Reproducible component tests using docker
PPTX
Kubernetes @ meetic
PPTX
Easy Java Integration Testing with Testcontainers​
PPTX
Introduction to TestContainers for Integration Testing
PDF
Testing containers with TestContainers @ AJUG 7/18/2017
PPTX
Integration testing for microservices with Spring Boot
PDF
Better Integration Tests for Kafka Applications with Testcontainers with Oleg...
PPTX
Testing your app
PDF
Using Docker for Testing - Mukta
GeeCON 2017 - TestContainers. Integration testing without the hassle
Level Up Your Integration Testing With Testcontainers
Simplifying Integration Testing in a Containerized World
Integration tests: use the containers, Luke!
Testcontainers - Geekout EE 2017 presentation
Testcontainers: Reliable, Isolated, and Reproducible Testing for External Dep...
Prod-Like Integration Testing for Distributed Containerized Applications
JBCN_Testing_With_Containers
JUnit5 and TestContainers
JLove - Replicating production on your laptop using the magic of containers
Take Control of your Integration Testing with TestContainers
Reproducible component tests using docker
Kubernetes @ meetic
Easy Java Integration Testing with Testcontainers​
Introduction to TestContainers for Integration Testing
Testing containers with TestContainers @ AJUG 7/18/2017
Integration testing for microservices with Spring Boot
Better Integration Tests for Kafka Applications with Testcontainers with Oleg...
Testing your app
Using Docker for Testing - Mukta
Ad

More from Anton Arhipov (20)

PDF
JavaZone 2022 - Building Kotlin DSL.pdf
PDF
Idiomatic kotlin
PDF
TechTrain 2019 - (Не)адекватное техническое интервью
PDF
Build pipelines with TeamCity
PDF
Build pipelines with TeamCity
PDF
Devoxx Ukraine 2018 - Kotlin DSL in under an hour
PDF
GeeCON Prague 2018 - Kotlin DSL in under an hour
PDF
Build pipelines with TeamCity and Kotlin DSL
PDF
Build pipelines with TeamCity
PDF
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
PDF
JavaZone 2017 - The Hitchhiker’s guide to Java class reloading
PDF
JUG.ua 20170225 - Java bytecode instrumentation
PDF
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
PDF
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
PDF
JEEConf 2017 - Having fun with Javassist
PDF
Devclub 01/2017 - (Не)адекватное Java-интервью
PDF
Joker 2016 - Bytecode 101
PDF
JPoint 2016 - Etudes of DIY Java profiler
PDF
JPoint 2016 - Bytecode
PDF
Riga Dev Day 2016 - Having fun with Javassist
JavaZone 2022 - Building Kotlin DSL.pdf
Idiomatic kotlin
TechTrain 2019 - (Не)адекватное техническое интервью
Build pipelines with TeamCity
Build pipelines with TeamCity
Devoxx Ukraine 2018 - Kotlin DSL in under an hour
GeeCON Prague 2018 - Kotlin DSL in under an hour
Build pipelines with TeamCity and Kotlin DSL
Build pipelines with TeamCity
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaZone 2017 - The Hitchhiker’s guide to Java class reloading
JUG.ua 20170225 - Java bytecode instrumentation
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - Having fun with Javassist
Devclub 01/2017 - (Не)адекватное Java-интервью
Joker 2016 - Bytecode 101
JPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Bytecode
Riga Dev Day 2016 - Having fun with Javassist

Recently uploaded (20)

PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPTX
sap open course for s4hana steps from ECC to s4
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PPTX
Cloud computing and distributed systems.
PDF
KodekX | Application Modernization Development
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
DOCX
The AUB Centre for AI in Media Proposal.docx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
Understanding_Digital_Forensics_Presentation.pptx
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
MYSQL Presentation for SQL database connectivity
Review of recent advances in non-invasive hemoglobin estimation
Mobile App Security Testing_ A Comprehensive Guide.pdf
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Reach Out and Touch Someone: Haptics and Empathic Computing
sap open course for s4hana steps from ECC to s4
MIND Revenue Release Quarter 2 2025 Press Release
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Spectral efficient network and resource selection model in 5G networks
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Cloud computing and distributed systems.
KodekX | Application Modernization Development
Building Integrated photovoltaic BIPV_UPV.pdf
The AUB Centre for AI in Media Proposal.docx
“AI and Expert System Decision Support & Business Intelligence Systems”
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Chapter 3 Spatial Domain Image Processing.pdf
Understanding_Digital_Forensics_Presentation.pptx

JavaOne 2017 - TestContainers: integration testing without the hassle

  • 9. 1. # of tests per time unit
  • 10. 1. # of tests per time unit 2. Complex setup
  • 13. 1. Reproducible environment 2. Both for development and CI
  • 14. 1. Reproducible environment 2. Both for development and CI 3. Isolated
  • 15. 1. Reproducible environment 2. Both for development and CI 3. Isolated 4. As real as possible
  • 16. 1. Reproducible environment 2. Both for development and CI 3. Isolated 4. As real as possible 5. Cross-platform
  • 17. 1. Reproducible environment 2. Both for development and CI 3. Isolated 4. As real as possible 5. Cross-platform 6. Easy to set up, use & maintain
  • 19. Docker Compose FTW! redis:
 image: redis
 ports:
 - "6379:6379"
 postgres:
 image: postgres
 ports:
 - "5432:5432"
 elasticsearch:
 image: elasticsearch:5.0.0
 ports:
 - "9200:9200"

  • 25. How does it work? https://github.com/docker-java/docker-java Docker environment discovery Will start docker machine if it’s not started yet Containers cleanup on JVM shutdown
  • 26. GenericContainer redis = new GenericContainer("redis:3.0.6") .withExposedPorts(6379);
  • 27. GenericContainer redis = new GenericContainer("redis:3.0.6") .withExposedPorts(6379); PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer("postgres:9.6.2") .withUsername(POSTGRES_USERNAME) .withPassword(POSTGRES_PASSWORD);
  • 29. Docker Compose? - Yes! public static DockerComposeContainer env = new DockerComposeContainer( new File("src/test/resources/compose-test.yml")) .withExposedService("redis_1", REDIS_PORT);
  • 30. Docker Compose? - Yes! public static DockerComposeContainer env = new DockerComposeContainer( new File("src/test/resources/compose-test.yml")) .withExposedService("redis_1", REDIS_PORT); String url = env.getServiceHost("redis_1", REDIS_PORT); Integer port = env.getServicePort("redis_1", REDIS_PORT); Jedis jedis = new Jedis(url, port);
  • 31. Microservices!11 REST service Java, Spring Boot Redis & PostgreSQL Calls some other micro-services
  • 32. @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class) public abstract class AbstractIntegrationTest { @ClassRule public static PostgreSQLContainer postgreSql = new PostgreSQLContainer(); @ClassRule public static GenericContainer redis = new GenericContainer("redis:3.0.6") .withExposedPorts(6379); @ClassRule public static MockServerContainer mockServer = new MockServerContainer();
  • 33. @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class) public abstract class AbstractIntegrationTest { @ClassRule public static PostgreSQLContainer postgreSql = new PostgreSQLContainer(); @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!
  • 34. @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class) public abstract class AbstractIntegrationTest { @ClassRule public static PostgreSQLContainer postgreSql = new PostgreSQLContainer(); @ClassRule public static GenericContainer redis = new GenericContainer("redis:3.0.6") .withExposedPorts(6379); @ClassRule public static MockServerContainer mockServer = new MockServerContainer(); External dependencies
  • 36. public class MockServerContainer<SELF extends MockServerContainer<SELF>> extends GenericContainer<SELF> { public MockServerContainer() { super("jamesdbloom/mockserver:latest"); addExposedPorts(8080); } private MockServerClient client; @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { super.containerIsStarted(containerInfo); client = new MockServerClient(getContainerIpAddress(), getMappedPort(getExposedPorts().get(0))); } }
  • 37. public class MockServerContainer<SELF extends MockServerContainer<SELF>> extends GenericContainer<SELF> { public MockServerContainer() { super("jamesdbloom/mockserver:latest"); addExposedPorts(8080); } private MockServerClient client; @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { super.containerIsStarted(containerInfo); client = new MockServerClient(getContainerIpAddress(), getMappedPort(getExposedPorts().get(0))); } }
  • 38. MockServerClient client = … client.when( HttpRequest.request("/analytics/issues/" + project.projectId + "/app").withMethod("GET"), Times.unlimited()) .respond(singleIssueResponse());
  • 41. How to test Java agents?
  • 42. public static void premain(String args, Instrumentation instrumentation) { instrumentation.addTransformer(new ClassFileTransformer() { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if ("spark/webserver/JettyHandler".equals(className)) { try { ClassPool cp = new ClassPool(); cp.appendClassPath(new LoaderClassPath(loader)); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer)); CtMethod ctMethod = ct.getDeclaredMethod("doHandle"); ctMethod.insertBefore("{ $4.setHeader("X-My-Super-Header", "header value"); }"); return ct.toBytecode(); } catch (Throwable e) { e.printStackTrace(); } } return classfileBuffer; } }); }
  • 43. public static void premain(String args, Instrumentation instrumentation) { instrumentation.addTransformer(new ClassFileTransformer() { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if ("spark/webserver/JettyHandler".equals(className)) { try { ClassPool cp = new ClassPool(); cp.appendClassPath(new LoaderClassPath(loader)); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer)); CtMethod ctMethod = ct.getDeclaredMethod("doHandle"); ctMethod.insertBefore("{ $4.setHeader("X-My-Super-Header", "header value"); }"); return ct.toBytecode(); } catch (Throwable e) { e.printStackTrace(); } } return classfileBuffer; } }); }
  • 44. public static void premain(String args, Instrumentation instrumentation) { instrumentation.addTransformer(new ClassFileTransformer() { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if ("spark/webserver/JettyHandler".equals(className)) { try { ClassPool cp = new ClassPool(); cp.appendClassPath(new LoaderClassPath(loader)); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer)); CtMethod ctMethod = ct.getDeclaredMethod("doHandle"); ctMethod.insertBefore("{ $4.setHeader("X-My-Super-Header", "header value"); }"); return ct.toBytecode(); } catch (Throwable e) { e.printStackTrace(); } } return classfileBuffer; } }); }
  • 45. public class AgentTest { @ClassRule public static BasicTestApp app = new BasicTestApp(); @Test public void testIt() throws Exception { Response response = app.getClient().getHello(); System.out.println("Got response:n" + response); assertThat(response.headers().get("X-My-Super-Header")) .isNotNull() .hasSize(1) .containsExactly("header value"); } }
  • 46. public class AgentTest { @ClassRule public static BasicTestApp app = new BasicTestApp(); @Test public void testIt() throws Exception { Response response = app.getClient().getHello(); System.out.println("Got response:n" + response); assertThat(response.headers().get("X-My-Super-Header")) .isNotNull() .hasSize(1) .containsExactly("header value"); } } A custom container
  • 47. public class AgentTest { @ClassRule public static BasicTestApp app = new BasicTestApp(); @Test public void testIt() throws Exception { Response response = app.getClient().getHello(); System.out.println("Got response:n" + response); assertThat(response.headers().get("X-My-Super-Header")) .isNotNull() .hasSize(1) .containsExactly("header value"); } } Verify, if the new behaviour is there