SlideShare a Scribd company logo
Testing For Unicorns
From Unit to Deployment Tests
Alex Soto

@alexsotob
@alexsotob2
Alex Soto
Red Hat Engineer
www.lordofthejars.com
@alexsotob
Who Am I?
@alexsotob3
https://www.manning.com/books/testing-java-microservices
@alexsotob4
Questions
@alexsotob5
Click to add subtitle
ASSERTIONS
@alexsotob
JUnit Test
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
assertEquals("Wolfgang Amadeus Mozart", mozart.getName());
assertEquals(Era.CLASSICAL, mozart.getEra());
assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate());
assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied());
}
6
@alexsotob
JUnit Test
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
assertEquals("Wolfgang Amadeus Mozart", mozart.getName());
assertEquals(Era.CLASSICAL, mozart.getEra());
assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate());
assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied());
}
6
Readable name
@alexsotob
JUnit Test
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
assertEquals("Wolfgang Amadeus Mozart", mozart.getName());
assertEquals(Era.CLASSICAL, mozart.getEra());
assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate());
assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied());
}
6
Readable name
BDD style
@alexsotob
JUnit Test
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
assertEquals("Wolfgang Amadeus Mozart", mozart.getName());
assertEquals(Era.CLASSICAL, mozart.getEra());
assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate());
assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied());
}
6
Readable name
BDD style
AssertEquals Order
@alexsotob
JUnit Test
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
assertEquals("Wolfgang Amadeus Mozart", mozart.getName());
assertEquals(Era.CLASSICAL, mozart.getEra());
assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate());
assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied());
}
6
Readable name
BDD style
AssertEquals Order
Depends On Equals
@alexsotob7
AssertJ
http://joel-costigliola.github.io/assertj/
@alexsotob
AssertJ Test
import static org.assertj.core.api.Assertions.assertThat;
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart”);
// Then:
assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart”);
assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName);
assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27));
assertThat(mozart).isEqualToComparingFieldByField(expectedMozart);
assertThat(mozart).isEqualToIgnoringNullFields(expectedMozart);
}
8
@alexsotob
AssertJ Test
import static org.assertj.core.api.Assertions.assertThat;
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart”);
// Then:
assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart”);
assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName);
assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27));
assertThat(mozart).isEqualToComparingFieldByField(expectedMozart);
assertThat(mozart).isEqualToIgnoringNullFields(expectedMozart);
}
8
Static Import
@alexsotob
AssertJ Test
import static org.assertj.core.api.Assertions.assertThat;
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart”);
// Then:
assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart”);
assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName);
assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27));
assertThat(mozart).isEqualToComparingFieldByField(expectedMozart);
assertThat(mozart).isEqualToIgnoringNullFields(expectedMozart);
}
8
Static Import
Readable Assertions
@alexsotob
AssertJ Test
import static org.assertj.core.api.Assertions.assertThat;
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart”);
// Then:
assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart”);
assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName);
assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27));
assertThat(mozart).isEqualToComparingFieldByField(expectedMozart);
assertThat(mozart).isEqualToIgnoringNullFields(expectedMozart);
}
8
Static Import
Readable Assertions
Not Depending on
Equals
@alexsotob
AssertJ Test Collections
@Test
public void should_find_operas_by_composer_name() {
// Given:
Composers composers = new Composers();
// When:
final List<Opera> operas = composers.findOperasByComposerName("Wolfgang Amadeus Mozart");
// Then:
assertThat(operas)
.hasSize(2)
.extracting(Opera::getName)
.containsExactlyInAnyOrder("Die Zauberflöte", "Don Giovanni”);
}
9
@alexsotob
AssertJ Test Collections
@Test
public void should_find_operas_by_composer_name() {
// Given:
Composers composers = new Composers();
// When:
final List<Opera> operas = composers.findOperasByComposerName("Wolfgang Amadeus Mozart");
// Then:
assertThat(operas)
.hasSize(2)
.extracting(Opera::getName)
.containsExactlyInAnyOrder("Die Zauberflöte", "Don Giovanni”);
}
9
Train Call (IDE
support)
@alexsotob
AssertJ Test Collections
@Test
public void should_find_operas_by_composer_name() {
// Given:
Composers composers = new Composers();
// When:
final List<Opera> operas = composers.findOperasByComposerName("Wolfgang Amadeus Mozart");
// Then:
assertThat(operas)
.hasSize(2)
.extracting(Opera::getName)
.containsExactlyInAnyOrder("Die Zauberflöte", "Don Giovanni”);
}
9
Train Call (IDE
support) Create List with
getName Result
@alexsotob
AssertJ Test Collections
@Test
public void should_find_operas_by_composer_name() {
// Given:
Composers composers = new Composers();
// When:
final List<Opera> operas = composers.findOperasByComposerName("Wolfgang Amadeus Mozart");
// Then:
assertThat(operas)
.hasSize(2)
.extracting(Opera::getName)
.containsExactlyInAnyOrder("Die Zauberflöte", "Don Giovanni”);
}
9
Train Call (IDE
support) Create List with
getName Result
Methods for String
@alexsotob
AssertJ Soft Assertions
@Test
public void should_find_composer_by_name_soft_assertions() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
SoftAssertions.assertSoftly(softly -> {
softly.assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart");
softly.assertThat(mozart.getEra()).isEqualTo(Era.CLASSICAL);
softly.assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27));
softly.assertThat(mozart.getDied()).isEqualTo(LocalDate.of(1791, 12, 5));
});
}
10
@alexsotob
AssertJ Soft Assertions
@Test
public void should_find_composer_by_name_soft_assertions() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
SoftAssertions.assertSoftly(softly -> {
softly.assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart");
softly.assertThat(mozart.getEra()).isEqualTo(Era.CLASSICAL);
softly.assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27));
softly.assertThat(mozart.getDied()).isEqualTo(LocalDate.of(1791, 12, 5));
});
}
10
Java 8 Lambda
@alexsotob
AssertJ Soft Assertions
@Test
public void should_find_composer_by_name_soft_assertions() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
SoftAssertions.assertSoftly(softly -> {
softly.assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart");
softly.assertThat(mozart.getEra()).isEqualTo(Era.CLASSICAL);
softly.assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27));
softly.assertThat(mozart.getDied()).isEqualTo(LocalDate.of(1791, 12, 5));
});
}
10
Java 8 Lambda
All assertions in Block
@alexsotob11
Don’t Sleep, Just Wait
@alexsotob
Asynchronous Call
@Test
public void should_play_operas() throws InterruptedException {
// Given:
final Opera nozzeDiFigaro = ...;
Gramophone gramophone = new Gramophone();
// When:
gramophone.play(nozzeDiFigaro);
// Then:
TimeUnit.SECONDS.sleep(3);
assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro);
}
12
@alexsotob
Asynchronous Call
@Test
public void should_play_operas() throws InterruptedException {
// Given:
final Opera nozzeDiFigaro = ...;
Gramophone gramophone = new Gramophone();
// When:
gramophone.play(nozzeDiFigaro);
// Then:
TimeUnit.SECONDS.sleep(3);
assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro);
}
12
Asynchronous Call
@alexsotob
Asynchronous Call
@Test
public void should_play_operas() throws InterruptedException {
// Given:
final Opera nozzeDiFigaro = ...;
Gramophone gramophone = new Gramophone();
// When:
gramophone.play(nozzeDiFigaro);
// Then:
TimeUnit.SECONDS.sleep(3);
assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro);
}
12
Asynchronous Call
Slowest Machine Time
@alexsotob13
https://github.com/awaitility/awaitility
@alexsotob
Awaitility Example
@Test
public void should_play_operas_version_2() {
// Given:
final Opera nozzeDiFigaro = Composers.OperaFactory
.createOpera("Le Nozze di Figaro")
.language(Language.ITALIAN).librettist("Lorenzo Da Ponte")
.roles("Count Almaviva", "Countess Rosina", "Susanna", "Figaro")
.build();
Gramophone gramophone = new Gramophone();
// When:
gramophone.play(nozzeDiFigaro);
// Then:
await().atMost(5, TimeUnit.SECONDS).until(gramophone::isPlaying);
assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro);
}
14
@alexsotob
Awaitility Example
@Test
public void should_play_operas_version_2() {
// Given:
final Opera nozzeDiFigaro = Composers.OperaFactory
.createOpera("Le Nozze di Figaro")
.language(Language.ITALIAN).librettist("Lorenzo Da Ponte")
.roles("Count Almaviva", "Countess Rosina", "Susanna", "Figaro")
.build();
Gramophone gramophone = new Gramophone();
// When:
gramophone.play(nozzeDiFigaro);
// Then:
await().atMost(5, TimeUnit.SECONDS).until(gramophone::isPlaying);
assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro);
}
14
Asynchronous Call
@alexsotob
Awaitility Example
@Test
public void should_play_operas_version_2() {
// Given:
final Opera nozzeDiFigaro = Composers.OperaFactory
.createOpera("Le Nozze di Figaro")
.language(Language.ITALIAN).librettist("Lorenzo Da Ponte")
.roles("Count Almaviva", "Countess Rosina", "Susanna", "Figaro")
.build();
Gramophone gramophone = new Gramophone();
// When:
gramophone.play(nozzeDiFigaro);
// Then:
await().atMost(5, TimeUnit.SECONDS).until(gramophone::isPlaying);
assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro);
}
14
Asynchronous Call
Polls until True or Timeout
@alexsotob
Deadlock Detection
Different Pollings
Fixed, Fibonacci, Iterative, Custom
Simple Library
No dependencies, No magic
Benefits of Awaitility
15
@alexsotob16
REST API
@alexsotob
GET /Ludwig+van+Beethoven
{
"name": "Ludwig van Beethoven",
"era": "ROMANTIC",
"birthdate": {},
"died": {},
"operas": [
{
"name": "Fidelio",
"librettist": "Georg Friedrich Treitschke",
"language": "GERMAN",
"roles": ["Rocco", "Leonore", "Florestan"]
}
]
}
17
@alexsotob
GET /Ludwig+van+Beethoven
{
"name": "Ludwig van Beethoven",
"era": "ROMANTIC",
"birthdate": {},
"died": {},
"operas": [
{
"name": "Fidelio",
"librettist": "Georg Friedrich Treitschke",
"language": "GERMAN",
"roles": ["Rocco", "Leonore", "Florestan"]
}
]
}
17
Simple Objects
@alexsotob
GET /Ludwig+van+Beethoven
{
"name": "Ludwig van Beethoven",
"era": "ROMANTIC",
"birthdate": {},
"died": {},
"operas": [
{
"name": "Fidelio",
"librettist": "Georg Friedrich Treitschke",
"language": "GERMAN",
"roles": ["Rocco", "Leonore", "Florestan"]
}
]
}
17
Simple Objects
Array of Objects
@alexsotob
HttpClient Example
@Test
public void should_find_composer() throws IOException, URISyntaxException {
// Given:
URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/");
uriBuilder.setPath("Ludwig van Beethoven");
// When:
final Content bodyContent = Request.Get(uriBuilder.build())
.execute().returnContent();
String body = bodyContent.asString();
// Then:
assertThat(body).contains(""name":"Ludwig van Beethoven"")
.contains(""librettist":"Georg Friedrich Treitschke"");
}
18
@alexsotob
HttpClient Example
@Test
public void should_find_composer() throws IOException, URISyntaxException {
// Given:
URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/");
uriBuilder.setPath("Ludwig van Beethoven");
// When:
final Content bodyContent = Request.Get(uriBuilder.build())
.execute().returnContent();
String body = bodyContent.asString();
// Then:
assertThat(body).contains(""name":"Ludwig van Beethoven"")
.contains(""librettist":"Georg Friedrich Treitschke"");
}
18
Prepare Connection
@alexsotob
HttpClient Example
@Test
public void should_find_composer() throws IOException, URISyntaxException {
// Given:
URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/");
uriBuilder.setPath("Ludwig van Beethoven");
// When:
final Content bodyContent = Request.Get(uriBuilder.build())
.execute().returnContent();
String body = bodyContent.asString();
// Then:
assertThat(body).contains(""name":"Ludwig van Beethoven"")
.contains(""librettist":"Georg Friedrich Treitschke"");
}
18
Prepare Connection
Do connection
@alexsotob
HttpClient Example
@Test
public void should_find_composer() throws IOException, URISyntaxException {
// Given:
URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/");
uriBuilder.setPath("Ludwig van Beethoven");
// When:
final Content bodyContent = Request.Get(uriBuilder.build())
.execute().returnContent();
String body = bodyContent.asString();
// Then:
assertThat(body).contains(""name":"Ludwig van Beethoven"")
.contains(""librettist":"Georg Friedrich Treitschke"");
}
18
Prepare Connection
Do connection
Get content
@alexsotob
HttpClient Example
@Test
public void should_find_composer() throws IOException, URISyntaxException {
// Given:
URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/");
uriBuilder.setPath("Ludwig van Beethoven");
// When:
final Content bodyContent = Request.Get(uriBuilder.build())
.execute().returnContent();
String body = bodyContent.asString();
// Then:
assertThat(body).contains(""name":"Ludwig van Beethoven"")
.contains(""librettist":"Georg Friedrich Treitschke"");
}
18
Prepare Connection
Do connection
Get content
Manipulate String
@alexsotob19
http://rest-assured.io/
@alexsotob
REST-assured Example
@Test
public void should_find_composer() {
given()
.when()
.get("{composer}", "Ludwig van Beethoven")
.then()
.assertThat()
.body("name", is("Ludwig van Beethoven"))
.body("operas.size()", is(1))
.body("operas.name", hasItems("Fidelio"));
}
20
@alexsotob
REST-assured Example
@Test
public void should_find_composer() {
given()
.when()
.get("{composer}", "Ludwig van Beethoven")
.then()
.assertThat()
.body("name", is("Ludwig van Beethoven"))
.body("operas.size()", is(1))
.body("operas.name", hasItems("Fidelio"));
}
20
GET Http Method with
Placeholders
@alexsotob
REST-assured Example
@Test
public void should_find_composer() {
given()
.when()
.get("{composer}", "Ludwig van Beethoven")
.then()
.assertThat()
.body("name", is("Ludwig van Beethoven"))
.body("operas.size()", is(1))
.body("operas.name", hasItems("Fidelio"));
}
20
GET Http Method with
Placeholders
GPath Expression
@alexsotob
REST-assured Request Specification
.get("http://example.com/{composer}", "Ludwig van Beethoven")
RequestSpecBuilder builder = new RequestSpecBuilder();
builder.setBaseUri("http://example.com");
given().spec(builder.build())...
21
@alexsotob
REST-assured Request Specification
.get("http://example.com/{composer}", "Ludwig van Beethoven")
RequestSpecBuilder builder = new RequestSpecBuilder();
builder.setBaseUri("http://example.com");
given().spec(builder.build())...
21
Use domain directly
@alexsotob
REST-assured Request Specification
.get("http://example.com/{composer}", "Ludwig van Beethoven")
RequestSpecBuilder builder = new RequestSpecBuilder();
builder.setBaseUri("http://example.com");
given().spec(builder.build())...
21
Use domain directly
Use Spec Builder
@alexsotob
REST-assured Request Specification
.get("http://example.com/{composer}", "Ludwig van Beethoven")
RequestSpecBuilder builder = new RequestSpecBuilder();
builder.setBaseUri("http://example.com");
given().spec(builder.build())...
21
Use domain directly
Use Spec Builder
Reuse Everywhere
@alexsotob
REST-assured Auth
given().auth().oauth2(accessToken).when()...
given().auth().form("John", "Doe", springSecurity().withCsrfFieldName("_csrf")).when()...
given().auth().basic("username", "password").when()...
22
@alexsotob
Custom Parsers
Not just JSON and XML
SSL Support
.relaxedHTTPSValidation()
Filters
Input/Output modification
JSON Schema Validation
Content not Important
More Features
of Rest-Assured
23
@alexsotob24
(Micro) Services Dependencies
@alexsotob
Network Down
Service Down
Limits on API
Component Not in Control
Micro-Services Dependencies Hell
Problems with Services
25
@alexsotob
Mock Http Component
Stub/Fake Http Server
Service Virtualization
Possible Solutions
26
@alexsotob27
Service Virtualization
@alexsotob27
Service Virtualization
@alexsotob
Service Virtualization Capture Mode
28
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Capture Mode
28
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Capture Mode
28
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Capture Mode
28
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Capture Mode
28
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Capture Mode
28
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Simulate Mode
29
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Simulate Mode
29
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Simulate Mode
29
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Simulate Mode
29
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Simulate Mode
29
Service A External Network Service B
Scripts
Proxy
@alexsotob30
https://hoverfly.io/
@alexsotob
Hoverfly Example
@ClassRule
public static HoverflyRule hoverflyRule =
HoverflyRule.inCaptureOrSimulationMode("getcomposers.json");
@Test
public void should_get_composers_from_composers_microservice() {
// Given:
ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081);
// When:
Composer composer = composersGateway.getComposer("Ludwig van Beethoven");
// Then:
assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven");
}
31
@alexsotob
Hoverfly Example
@ClassRule
public static HoverflyRule hoverflyRule =
HoverflyRule.inCaptureOrSimulationMode("getcomposers.json");
@Test
public void should_get_composers_from_composers_microservice() {
// Given:
ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081);
// When:
Composer composer = composersGateway.getComposer("Ludwig van Beethoven");
// Then:
assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven");
}
31
Start Hoverfly
@alexsotob
Hoverfly Example
@ClassRule
public static HoverflyRule hoverflyRule =
HoverflyRule.inCaptureOrSimulationMode("getcomposers.json");
@Test
public void should_get_composers_from_composers_microservice() {
// Given:
ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081);
// When:
Composer composer = composersGateway.getComposer("Ludwig van Beethoven");
// Then:
assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven");
}
31
Start Hoverfly
Use Real Host
@alexsotob
Hoverfly Example
@ClassRule
public static HoverflyRule hoverflyRule =
HoverflyRule.inCaptureOrSimulationMode("getcomposers.json");
@Test
public void should_get_composers_from_composers_microservice() {
// Given:
ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081);
// When:
Composer composer = composersGateway.getComposer("Ludwig van Beethoven");
// Then:
assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven");
}
31
Start Hoverfly
Use Real Host
Get Data from Real
@alexsotob
Hoverfly Example
@ClassRule
public static HoverflyRule hoverflyRule =
HoverflyRule.inCaptureOrSimulationMode("getcomposers.json");
@Test
public void should_get_composers_from_composers_microservice() {
// Given:
ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081);
// When:
Composer composer = composersGateway.getComposer("Ludwig van Beethoven");
// Then:
assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven");
}
31
Start Hoverfly
Use Real Host
Get Data from Real
{
"data" : {
"pairs" : [{
"request" : {
"path" : "/Ludwig van Beethoven",
"method" : "GET",
"destination" : “operas.com:8081",
...
}
"response" : {
"status" : 200,
"body" : "{"name":"Ludwig van Beethoven",}",
"encodedBody" : false,
"headers" : {
"Connection" : [ "keep-alive" ],
...
}
}
}
}
@alexsotob
Hoverfly Example
@ClassRule
public static HoverflyRule hoverflyRule =
HoverflyRule.inCaptureOrSimulationMode("getcomposers.json");
@Test
public void should_get_composers_from_composers_microservice() {
// Given:
ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081);
// When:
Composer composer = composersGateway.getComposer("Ludwig van Beethoven");
// Then:
assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven");
}
31
Start Hoverfly
Use Real Host
Get Data from Real
@alexsotob
Hoverfly Example
@ClassRule
public static HoverflyRule hoverflyRule =
HoverflyRule.inCaptureOrSimulationMode("getcomposers.json");
@Test
public void should_get_composers_from_composers_microservice() {
// Given:
ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081);
// When:
Composer composer = composersGateway.getComposer("Ludwig van Beethoven");
// Then:
assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven");
}
31
Start Hoverfly
Use Real Host
Get Data from Proxy
@alexsotob32
Containers Are Burning
@alexsotob32
Containers Are Burning
@alexsotob
Testing Containers
docker build -t myorg/myservice:1.0.0 .
docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0
docker-compose up
mvn clean test
docker-compose stop
33
@alexsotob
Testing Containers
docker build -t myorg/myservice:1.0.0 .
docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0
docker-compose up
mvn clean test
docker-compose stop
33
Docker Run
@alexsotob
Testing Containers
docker build -t myorg/myservice:1.0.0 .
docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0
docker-compose up
mvn clean test
docker-compose stop
33
Docker Run
Docker Compose Run
@alexsotob
Testing Containers
docker build -t myorg/myservice:1.0.0 .
docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0
docker-compose up
mvn clean test
docker-compose stop
33
Docker Run
Docker Compose Run
Run tests
@alexsotob
Testing Containers
docker build -t myorg/myservice:1.0.0 .
docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0
docker-compose up
mvn clean test
docker-compose stop
33
Docker Run
Docker Compose Run
Run tests
Stop Docker Containers
@alexsotob34
http://arquillian.org/arquillian-cube/
@alexsotob
Arquillian Cube Example
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
@DockerUrl(containerName = "helloworld", exposedPort = 8080)
RequestSpecBuilder requestSpecBuilder;
@Test
public void should_receive_ok_message() {
RestAssured
.given()
.spec(requestSpecBuilder.build())
.when()
.get()
.then()
.assertThat().body("status", equalTo("OK"));
}
}
35
@alexsotob
Arquillian Cube Example
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
@DockerUrl(containerName = "helloworld", exposedPort = 8080)
RequestSpecBuilder requestSpecBuilder;
@Test
public void should_receive_ok_message() {
RestAssured
.given()
.spec(requestSpecBuilder.build())
.when()
.get()
.then()
.assertThat().body("status", equalTo("OK"));
}
}
35
Arquillian Runner
@alexsotob
Arquillian Cube Example
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
@DockerUrl(containerName = "helloworld", exposedPort = 8080)
RequestSpecBuilder requestSpecBuilder;
@Test
public void should_receive_ok_message() {
RestAssured
.given()
.spec(requestSpecBuilder.build())
.when()
.get()
.then()
.assertThat().body("status", equalTo("OK"));
}
}
35
Arquillian Runner
REST-Assured Integration
Environment Resolver
@alexsotob
Arquillian Cube Example
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
@DockerUrl(containerName = "helloworld", exposedPort = 8080)
RequestSpecBuilder requestSpecBuilder;
@Test
public void should_receive_ok_message() {
RestAssured
.given()
.spec(requestSpecBuilder.build())
.when()
.get()
.then()
.assertThat().body("status", equalTo("OK"));
}
}
35
Arquillian Runner
REST-Assured Integration
Environment Resolver
Normal REST-Assured Call
@alexsotob
Arquillian Cube Example
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
@DockerUrl(containerName = "helloworld", exposedPort = 8080)
RequestSpecBuilder requestSpecBuilder;
@Test
public void should_receive_ok_message() {
RestAssured
.given()
.spec(requestSpecBuilder.build())
.when()
.get()
.then()
.assertThat().body("status", equalTo("OK"));
}
}
35
Arquillian Runner
REST-Assured Integration
Environment Resolver
Normal REST-Assured Call
helloworld:
image: jonmorehouse/ping-pong
ports:
- "8080:8080"
src/test/docker/docker-compose.yml
@alexsotob
Arquillian Cube DSL
@RunWith(SpringRunner.class)
@SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT)
@ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class)
public class PingPongSpringBootTest {
@ClassRule
public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
.withPortBinding(6379);
@Autowired
TestRestTemplate restTemplate;
@Test
public void should_get_data_from_redis() {
}
36
@alexsotob
Arquillian Cube DSL
@RunWith(SpringRunner.class)
@SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT)
@ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class)
public class PingPongSpringBootTest {
@ClassRule
public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
.withPortBinding(6379);
@Autowired
TestRestTemplate restTemplate;
@Test
public void should_get_data_from_redis() {
}
36
Spring Boot Test
@alexsotob
Arquillian Cube DSL
@RunWith(SpringRunner.class)
@SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT)
@ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class)
public class PingPongSpringBootTest {
@ClassRule
public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
.withPortBinding(6379);
@Autowired
TestRestTemplate restTemplate;
@Test
public void should_get_data_from_redis() {
}
36
Spring Boot Test
Custom Initializer
@alexsotob
Arquillian Cube DSL
@RunWith(SpringRunner.class)
@SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT)
@ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class)
public class PingPongSpringBootTest {
@ClassRule
public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
.withPortBinding(6379);
@Autowired
TestRestTemplate restTemplate;
@Test
public void should_get_data_from_redis() {
}
36
Spring Boot Test
Custom Initializer
Container Definition
@alexsotob
Arquillian Cube DSL
@RunWith(SpringRunner.class)
@SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT)
@ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class)
public class PingPongSpringBootTest {
@ClassRule
public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
.withPortBinding(6379);
@Autowired
TestRestTemplate restTemplate;
@Test
public void should_get_data_from_redis() {
}
36
Spring Boot Test
Custom Initializer
Container Definition
public static class Initializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
EnvironmentTestUtils.addEnvironment("testcontainers",
configurableApplicationContext.getEnvironment(),
"spring.redis.host=" + redis.getIpAddress(),
"spring.redis.port=" + redis.getBindPort(6379)
);
@alexsotob
Arquillian Cube DSL
@RunWith(SpringRunner.class)
@SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT)
@ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class)
public class PingPongSpringBootTest {
@ClassRule
public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
.withPortBinding(6379);
@Autowired
TestRestTemplate restTemplate;
@Test
public void should_get_data_from_redis() {
}
36
Spring Boot Test
Custom Initializer
Container Definition
public static class Initializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
EnvironmentTestUtils.addEnvironment("testcontainers",
configurableApplicationContext.getEnvironment(),
"spring.redis.host=" + redis.getIpAddress(),
"spring.redis.port=" + redis.getBindPort(6379)
);
Sets Container Environment
@alexsotob
Arquillian Cube K8S/OpenShift
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
KubernetesClient client;
@Named("hello-world-service")
@PortForward
@ArquillianResource
URL url;
@Test
public void testRunningPodStaysUp() throws Exception {
assertThat(client).deployments().pods().isPodReadyForPeriod();
}
}
37
@alexsotob
Arquillian Cube K8S/OpenShift
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
KubernetesClient client;
@Named("hello-world-service")
@PortForward
@ArquillianResource
URL url;
@Test
public void testRunningPodStaysUp() throws Exception {
assertThat(client).deployments().pods().isPodReadyForPeriod();
}
}
37
Kubernetes Client
@alexsotob
Arquillian Cube K8S/OpenShift
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
KubernetesClient client;
@Named("hello-world-service")
@PortForward
@ArquillianResource
URL url;
@Test
public void testRunningPodStaysUp() throws Exception {
assertThat(client).deployments().pods().isPodReadyForPeriod();
}
}
37
Kubernetes Client
URL to Access Service
@alexsotob
Arquillian Cube K8S/OpenShift
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
KubernetesClient client;
@Named("hello-world-service")
@PortForward
@ArquillianResource
URL url;
@Test
public void testRunningPodStaysUp() throws Exception {
assertThat(client).deployments().pods().isPodReadyForPeriod();
}
}
37
Kubernetes Client
URL to Access Service
AssertJ Custom Assertions
@alexsotob38
Smart Testing
http://arquillian.org/smart-testing/
@alexsotob39
Production Sources Tests
https://martinfowler.com/articles/rise-test-impact-analysis.html
@alexsotob39
Production Sources Tests
https://martinfowler.com/articles/rise-test-impact-analysis.html
@alexsotob39
Production Sources Tests
https://martinfowler.com/articles/rise-test-impact-analysis.html
@alexsotob
Smart Testing Maven Extension
curl -sSL https://git.io/v5jy6 | bash
40
@alexsotob
Smart Testing Maven Extension
curl -sSL https://git.io/v5jy6 | bash
40
Installs extension
@alexsotob
Smart Testing Maven Extension
curl -sSL https://git.io/v5jy6 | bash
40
Installs extension
mvn clean test -Dsmart.testing="new, changed, affected"
@alexsotob
Smart Testing Maven Extension
curl -sSL https://git.io/v5jy6 | bash
40
Installs extension
mvn clean test -Dsmart.testing="new, changed, affected"
Runs ONLY new, changed and prod related tests
@alexsotob
Smart Testing Maven Extension
curl -sSL https://git.io/v5jy6 | bash
40
Installs extension
mvn clean test -Dsmart.testing="new, changed, affected"
Runs ONLY new, changed and prod related tests
mvn clean test -Dsmart.testing.mode=ordering -Dsmart.testing="new, changed, affected”
@alexsotob
Smart Testing Maven Extension
curl -sSL https://git.io/v5jy6 | bash
40
Installs extension
mvn clean test -Dsmart.testing="new, changed, affected"
Runs ONLY new, changed and prod related tests
mvn clean test -Dsmart.testing.mode=ordering -Dsmart.testing="new, changed, affected”
Prioritize new, changed and prod related tests
@alexsotob41
Let’s Wind Down
@alexsotob
From Low to High Level
Unit, Component, Integration, Deployment
Not Just for Micro-Services
Same can be reused for monolithic
Improves Readability
Tests are meant to be read
Conclusions
42
Deployment Velocity
From week to several times per day
@alexsotob43
Keep Calm
And Write Tests
http://bit.ly/2xT2syU

More Related Content

PDF
Testing Java Microservices Devoxx be 2017
PDF
Testing for Unicorns
PDF
10 Testing libraries any Java developer should know
PDF
Testing in the 21st Century
PDF
MCE^3 - Jorge D. Ortiz - Fuentes - Escape From Mars
PDF
Idiomatic spock
PDF
Testing with Kotlin
PDF
Testing Java Code Effectively
Testing Java Microservices Devoxx be 2017
Testing for Unicorns
10 Testing libraries any Java developer should know
Testing in the 21st Century
MCE^3 - Jorge D. Ortiz - Fuentes - Escape From Mars
Idiomatic spock
Testing with Kotlin
Testing Java Code Effectively

What's hot (20)

PDF
Checking Bitcoin
PDF
Making the most of your gradle build - Gr8Conf 2017
PDF
Making the most of your gradle build - Greach 2017
PDF
Escape from Mars
PDF
JavaOne 2017 - TestContainers: integration testing without the hassle
PDF
HOW TO DEAL WITH BLOCKING CODE WITHIN ASYNCIO EVENT LOOP
PDF
BUILDING APPS WITH ASYNCIO
PDF
Agile Android
PDF
Con-FESS 2015 - Having Fun With Javassist
PPTX
Dead-Simple Async Control Flow with Coroutines
PPTX
Java Libraries You Can’t Afford to Miss
PDF
Java Libraries You Can’t Afford to Miss
PDF
Voxxed Days Vilnius 2015 - Having fun with Javassist
PDF
Agile Swift
PDF
Una Critica a Rails by Luca Guidi
PDF
Oredev 2015 - Taming Java Agents
PDF
Going On with the Check of Geant4
PDF
GitGot: The Swiss Army Chainsaw of Git Repo Management
ODP
Trash Robotic Router Platform
PDF
Making the Most of Your Gradle Build
Checking Bitcoin
Making the most of your gradle build - Gr8Conf 2017
Making the most of your gradle build - Greach 2017
Escape from Mars
JavaOne 2017 - TestContainers: integration testing without the hassle
HOW TO DEAL WITH BLOCKING CODE WITHIN ASYNCIO EVENT LOOP
BUILDING APPS WITH ASYNCIO
Agile Android
Con-FESS 2015 - Having Fun With Javassist
Dead-Simple Async Control Flow with Coroutines
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
Voxxed Days Vilnius 2015 - Having fun with Javassist
Agile Swift
Una Critica a Rails by Luca Guidi
Oredev 2015 - Taming Java Agents
Going On with the Check of Geant4
GitGot: The Swiss Army Chainsaw of Git Repo Management
Trash Robotic Router Platform
Making the Most of Your Gradle Build
Ad

Similar to Testing For Unicorns [IMWorld] (7)

PDF
Testing For Unicorns
PDF
JavaScript - new features in ECMAScript 6
PDF
Expression trees in c#
ODP
Ast transformations
ODP
AST Transformations
PPTX
Expression trees in c#, Алексей Голубь (Svitla Systems)
PDF
Unbearable Test Code Smell
Testing For Unicorns
JavaScript - new features in ECMAScript 6
Expression trees in c#
Ast transformations
AST Transformations
Expression trees in c#, Алексей Голубь (Svitla Systems)
Unbearable Test Code Smell
Ad

More from Alex Soto (20)

PDF
Kubernetes Native Java
PDF
Reactive Programming for Real Use Cases
PDF
Chaos Engineering Kubernetes
PDF
Chaos Engineering Kubernetes
PDF
Microservices testing and automation
PDF
Testing in Production: From DevTestOops to DevTestOps
PDF
Supersonic Subatomic Java
PDF
From DevTestOops to DevTestOps
PDF
Istio service mesh & pragmatic microservices architecture
PDF
Zero Downtime Deployment in Microservices era
PDF
Service Mesh Patterns
PDF
Supersonic, Subatomic Java
PDF
Zero Downtime Deployment in Microservices era
PDF
Long Live and Prosper To Monolith
PDF
Sail in the cloud - An intro to Istio commit
PDF
KubeBoot - Spring Boot deployment on Kubernetes
PDF
Sail in the Cloud - An intro to Istio
PDF
Testing XXIst Century
PDF
Arquillian Constellation
PDF
Live Long and Prosper to Monolith
Kubernetes Native Java
Reactive Programming for Real Use Cases
Chaos Engineering Kubernetes
Chaos Engineering Kubernetes
Microservices testing and automation
Testing in Production: From DevTestOops to DevTestOps
Supersonic Subatomic Java
From DevTestOops to DevTestOps
Istio service mesh & pragmatic microservices architecture
Zero Downtime Deployment in Microservices era
Service Mesh Patterns
Supersonic, Subatomic Java
Zero Downtime Deployment in Microservices era
Long Live and Prosper To Monolith
Sail in the cloud - An intro to Istio commit
KubeBoot - Spring Boot deployment on Kubernetes
Sail in the Cloud - An intro to Istio
Testing XXIst Century
Arquillian Constellation
Live Long and Prosper to Monolith

Recently uploaded (20)

PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Digital Strategies for Manufacturing Companies
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PPTX
history of c programming in notes for students .pptx
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PPTX
Computer Software and OS of computer science of grade 11.pptx
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Digital Systems & Binary Numbers (comprehensive )
PDF
Designing Intelligence for the Shop Floor.pdf
PDF
top salesforce developer skills in 2025.pdf
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
Which alternative to Crystal Reports is best for small or large businesses.pdf
Digital Strategies for Manufacturing Companies
Odoo Companies in India – Driving Business Transformation.pdf
Adobe Illustrator 28.6 Crack My Vision of Vector Design
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
Design an Analysis of Algorithms II-SECS-1021-03
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
Operating system designcfffgfgggggggvggggggggg
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
history of c programming in notes for students .pptx
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Internet Downloader Manager (IDM) Crack 6.42 Build 41
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Computer Software and OS of computer science of grade 11.pptx
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Digital Systems & Binary Numbers (comprehensive )
Designing Intelligence for the Shop Floor.pdf
top salesforce developer skills in 2025.pdf
Navsoft: AI-Powered Business Solutions & Custom Software Development
Upgrade and Innovation Strategies for SAP ERP Customers

Testing For Unicorns [IMWorld]

  • 1. Testing For Unicorns From Unit to Deployment Tests Alex Soto
 @alexsotob
  • 2. @alexsotob2 Alex Soto Red Hat Engineer www.lordofthejars.com @alexsotob Who Am I?
  • 5. @alexsotob5 Click to add subtitle ASSERTIONS
  • 6. @alexsotob JUnit Test @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart"); // Then: assertEquals("Wolfgang Amadeus Mozart", mozart.getName()); assertEquals(Era.CLASSICAL, mozart.getEra()); assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate()); assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied()); } 6
  • 7. @alexsotob JUnit Test @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart"); // Then: assertEquals("Wolfgang Amadeus Mozart", mozart.getName()); assertEquals(Era.CLASSICAL, mozart.getEra()); assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate()); assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied()); } 6 Readable name
  • 8. @alexsotob JUnit Test @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart"); // Then: assertEquals("Wolfgang Amadeus Mozart", mozart.getName()); assertEquals(Era.CLASSICAL, mozart.getEra()); assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate()); assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied()); } 6 Readable name BDD style
  • 9. @alexsotob JUnit Test @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart"); // Then: assertEquals("Wolfgang Amadeus Mozart", mozart.getName()); assertEquals(Era.CLASSICAL, mozart.getEra()); assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate()); assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied()); } 6 Readable name BDD style AssertEquals Order
  • 10. @alexsotob JUnit Test @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart"); // Then: assertEquals("Wolfgang Amadeus Mozart", mozart.getName()); assertEquals(Era.CLASSICAL, mozart.getEra()); assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate()); assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied()); } 6 Readable name BDD style AssertEquals Order Depends On Equals
  • 12. @alexsotob AssertJ Test import static org.assertj.core.api.Assertions.assertThat; @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart”); // Then: assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart”); assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName); assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27)); assertThat(mozart).isEqualToComparingFieldByField(expectedMozart); assertThat(mozart).isEqualToIgnoringNullFields(expectedMozart); } 8
  • 13. @alexsotob AssertJ Test import static org.assertj.core.api.Assertions.assertThat; @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart”); // Then: assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart”); assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName); assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27)); assertThat(mozart).isEqualToComparingFieldByField(expectedMozart); assertThat(mozart).isEqualToIgnoringNullFields(expectedMozart); } 8 Static Import
  • 14. @alexsotob AssertJ Test import static org.assertj.core.api.Assertions.assertThat; @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart”); // Then: assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart”); assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName); assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27)); assertThat(mozart).isEqualToComparingFieldByField(expectedMozart); assertThat(mozart).isEqualToIgnoringNullFields(expectedMozart); } 8 Static Import Readable Assertions
  • 15. @alexsotob AssertJ Test import static org.assertj.core.api.Assertions.assertThat; @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart”); // Then: assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart”); assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName); assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27)); assertThat(mozart).isEqualToComparingFieldByField(expectedMozart); assertThat(mozart).isEqualToIgnoringNullFields(expectedMozart); } 8 Static Import Readable Assertions Not Depending on Equals
  • 16. @alexsotob AssertJ Test Collections @Test public void should_find_operas_by_composer_name() { // Given: Composers composers = new Composers(); // When: final List<Opera> operas = composers.findOperasByComposerName("Wolfgang Amadeus Mozart"); // Then: assertThat(operas) .hasSize(2) .extracting(Opera::getName) .containsExactlyInAnyOrder("Die Zauberflöte", "Don Giovanni”); } 9
  • 17. @alexsotob AssertJ Test Collections @Test public void should_find_operas_by_composer_name() { // Given: Composers composers = new Composers(); // When: final List<Opera> operas = composers.findOperasByComposerName("Wolfgang Amadeus Mozart"); // Then: assertThat(operas) .hasSize(2) .extracting(Opera::getName) .containsExactlyInAnyOrder("Die Zauberflöte", "Don Giovanni”); } 9 Train Call (IDE support)
  • 18. @alexsotob AssertJ Test Collections @Test public void should_find_operas_by_composer_name() { // Given: Composers composers = new Composers(); // When: final List<Opera> operas = composers.findOperasByComposerName("Wolfgang Amadeus Mozart"); // Then: assertThat(operas) .hasSize(2) .extracting(Opera::getName) .containsExactlyInAnyOrder("Die Zauberflöte", "Don Giovanni”); } 9 Train Call (IDE support) Create List with getName Result
  • 19. @alexsotob AssertJ Test Collections @Test public void should_find_operas_by_composer_name() { // Given: Composers composers = new Composers(); // When: final List<Opera> operas = composers.findOperasByComposerName("Wolfgang Amadeus Mozart"); // Then: assertThat(operas) .hasSize(2) .extracting(Opera::getName) .containsExactlyInAnyOrder("Die Zauberflöte", "Don Giovanni”); } 9 Train Call (IDE support) Create List with getName Result Methods for String
  • 20. @alexsotob AssertJ Soft Assertions @Test public void should_find_composer_by_name_soft_assertions() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart"); // Then: SoftAssertions.assertSoftly(softly -> { softly.assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart"); softly.assertThat(mozart.getEra()).isEqualTo(Era.CLASSICAL); softly.assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27)); softly.assertThat(mozart.getDied()).isEqualTo(LocalDate.of(1791, 12, 5)); }); } 10
  • 21. @alexsotob AssertJ Soft Assertions @Test public void should_find_composer_by_name_soft_assertions() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart"); // Then: SoftAssertions.assertSoftly(softly -> { softly.assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart"); softly.assertThat(mozart.getEra()).isEqualTo(Era.CLASSICAL); softly.assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27)); softly.assertThat(mozart.getDied()).isEqualTo(LocalDate.of(1791, 12, 5)); }); } 10 Java 8 Lambda
  • 22. @alexsotob AssertJ Soft Assertions @Test public void should_find_composer_by_name_soft_assertions() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart"); // Then: SoftAssertions.assertSoftly(softly -> { softly.assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart"); softly.assertThat(mozart.getEra()).isEqualTo(Era.CLASSICAL); softly.assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27)); softly.assertThat(mozart.getDied()).isEqualTo(LocalDate.of(1791, 12, 5)); }); } 10 Java 8 Lambda All assertions in Block
  • 24. @alexsotob Asynchronous Call @Test public void should_play_operas() throws InterruptedException { // Given: final Opera nozzeDiFigaro = ...; Gramophone gramophone = new Gramophone(); // When: gramophone.play(nozzeDiFigaro); // Then: TimeUnit.SECONDS.sleep(3); assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro); } 12
  • 25. @alexsotob Asynchronous Call @Test public void should_play_operas() throws InterruptedException { // Given: final Opera nozzeDiFigaro = ...; Gramophone gramophone = new Gramophone(); // When: gramophone.play(nozzeDiFigaro); // Then: TimeUnit.SECONDS.sleep(3); assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro); } 12 Asynchronous Call
  • 26. @alexsotob Asynchronous Call @Test public void should_play_operas() throws InterruptedException { // Given: final Opera nozzeDiFigaro = ...; Gramophone gramophone = new Gramophone(); // When: gramophone.play(nozzeDiFigaro); // Then: TimeUnit.SECONDS.sleep(3); assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro); } 12 Asynchronous Call Slowest Machine Time
  • 28. @alexsotob Awaitility Example @Test public void should_play_operas_version_2() { // Given: final Opera nozzeDiFigaro = Composers.OperaFactory .createOpera("Le Nozze di Figaro") .language(Language.ITALIAN).librettist("Lorenzo Da Ponte") .roles("Count Almaviva", "Countess Rosina", "Susanna", "Figaro") .build(); Gramophone gramophone = new Gramophone(); // When: gramophone.play(nozzeDiFigaro); // Then: await().atMost(5, TimeUnit.SECONDS).until(gramophone::isPlaying); assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro); } 14
  • 29. @alexsotob Awaitility Example @Test public void should_play_operas_version_2() { // Given: final Opera nozzeDiFigaro = Composers.OperaFactory .createOpera("Le Nozze di Figaro") .language(Language.ITALIAN).librettist("Lorenzo Da Ponte") .roles("Count Almaviva", "Countess Rosina", "Susanna", "Figaro") .build(); Gramophone gramophone = new Gramophone(); // When: gramophone.play(nozzeDiFigaro); // Then: await().atMost(5, TimeUnit.SECONDS).until(gramophone::isPlaying); assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro); } 14 Asynchronous Call
  • 30. @alexsotob Awaitility Example @Test public void should_play_operas_version_2() { // Given: final Opera nozzeDiFigaro = Composers.OperaFactory .createOpera("Le Nozze di Figaro") .language(Language.ITALIAN).librettist("Lorenzo Da Ponte") .roles("Count Almaviva", "Countess Rosina", "Susanna", "Figaro") .build(); Gramophone gramophone = new Gramophone(); // When: gramophone.play(nozzeDiFigaro); // Then: await().atMost(5, TimeUnit.SECONDS).until(gramophone::isPlaying); assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro); } 14 Asynchronous Call Polls until True or Timeout
  • 31. @alexsotob Deadlock Detection Different Pollings Fixed, Fibonacci, Iterative, Custom Simple Library No dependencies, No magic Benefits of Awaitility 15
  • 33. @alexsotob GET /Ludwig+van+Beethoven { "name": "Ludwig van Beethoven", "era": "ROMANTIC", "birthdate": {}, "died": {}, "operas": [ { "name": "Fidelio", "librettist": "Georg Friedrich Treitschke", "language": "GERMAN", "roles": ["Rocco", "Leonore", "Florestan"] } ] } 17
  • 34. @alexsotob GET /Ludwig+van+Beethoven { "name": "Ludwig van Beethoven", "era": "ROMANTIC", "birthdate": {}, "died": {}, "operas": [ { "name": "Fidelio", "librettist": "Georg Friedrich Treitschke", "language": "GERMAN", "roles": ["Rocco", "Leonore", "Florestan"] } ] } 17 Simple Objects
  • 35. @alexsotob GET /Ludwig+van+Beethoven { "name": "Ludwig van Beethoven", "era": "ROMANTIC", "birthdate": {}, "died": {}, "operas": [ { "name": "Fidelio", "librettist": "Georg Friedrich Treitschke", "language": "GERMAN", "roles": ["Rocco", "Leonore", "Florestan"] } ] } 17 Simple Objects Array of Objects
  • 36. @alexsotob HttpClient Example @Test public void should_find_composer() throws IOException, URISyntaxException { // Given: URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/"); uriBuilder.setPath("Ludwig van Beethoven"); // When: final Content bodyContent = Request.Get(uriBuilder.build()) .execute().returnContent(); String body = bodyContent.asString(); // Then: assertThat(body).contains(""name":"Ludwig van Beethoven"") .contains(""librettist":"Georg Friedrich Treitschke""); } 18
  • 37. @alexsotob HttpClient Example @Test public void should_find_composer() throws IOException, URISyntaxException { // Given: URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/"); uriBuilder.setPath("Ludwig van Beethoven"); // When: final Content bodyContent = Request.Get(uriBuilder.build()) .execute().returnContent(); String body = bodyContent.asString(); // Then: assertThat(body).contains(""name":"Ludwig van Beethoven"") .contains(""librettist":"Georg Friedrich Treitschke""); } 18 Prepare Connection
  • 38. @alexsotob HttpClient Example @Test public void should_find_composer() throws IOException, URISyntaxException { // Given: URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/"); uriBuilder.setPath("Ludwig van Beethoven"); // When: final Content bodyContent = Request.Get(uriBuilder.build()) .execute().returnContent(); String body = bodyContent.asString(); // Then: assertThat(body).contains(""name":"Ludwig van Beethoven"") .contains(""librettist":"Georg Friedrich Treitschke""); } 18 Prepare Connection Do connection
  • 39. @alexsotob HttpClient Example @Test public void should_find_composer() throws IOException, URISyntaxException { // Given: URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/"); uriBuilder.setPath("Ludwig van Beethoven"); // When: final Content bodyContent = Request.Get(uriBuilder.build()) .execute().returnContent(); String body = bodyContent.asString(); // Then: assertThat(body).contains(""name":"Ludwig van Beethoven"") .contains(""librettist":"Georg Friedrich Treitschke""); } 18 Prepare Connection Do connection Get content
  • 40. @alexsotob HttpClient Example @Test public void should_find_composer() throws IOException, URISyntaxException { // Given: URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/"); uriBuilder.setPath("Ludwig van Beethoven"); // When: final Content bodyContent = Request.Get(uriBuilder.build()) .execute().returnContent(); String body = bodyContent.asString(); // Then: assertThat(body).contains(""name":"Ludwig van Beethoven"") .contains(""librettist":"Georg Friedrich Treitschke""); } 18 Prepare Connection Do connection Get content Manipulate String
  • 42. @alexsotob REST-assured Example @Test public void should_find_composer() { given() .when() .get("{composer}", "Ludwig van Beethoven") .then() .assertThat() .body("name", is("Ludwig van Beethoven")) .body("operas.size()", is(1)) .body("operas.name", hasItems("Fidelio")); } 20
  • 43. @alexsotob REST-assured Example @Test public void should_find_composer() { given() .when() .get("{composer}", "Ludwig van Beethoven") .then() .assertThat() .body("name", is("Ludwig van Beethoven")) .body("operas.size()", is(1)) .body("operas.name", hasItems("Fidelio")); } 20 GET Http Method with Placeholders
  • 44. @alexsotob REST-assured Example @Test public void should_find_composer() { given() .when() .get("{composer}", "Ludwig van Beethoven") .then() .assertThat() .body("name", is("Ludwig van Beethoven")) .body("operas.size()", is(1)) .body("operas.name", hasItems("Fidelio")); } 20 GET Http Method with Placeholders GPath Expression
  • 45. @alexsotob REST-assured Request Specification .get("http://example.com/{composer}", "Ludwig van Beethoven") RequestSpecBuilder builder = new RequestSpecBuilder(); builder.setBaseUri("http://example.com"); given().spec(builder.build())... 21
  • 46. @alexsotob REST-assured Request Specification .get("http://example.com/{composer}", "Ludwig van Beethoven") RequestSpecBuilder builder = new RequestSpecBuilder(); builder.setBaseUri("http://example.com"); given().spec(builder.build())... 21 Use domain directly
  • 47. @alexsotob REST-assured Request Specification .get("http://example.com/{composer}", "Ludwig van Beethoven") RequestSpecBuilder builder = new RequestSpecBuilder(); builder.setBaseUri("http://example.com"); given().spec(builder.build())... 21 Use domain directly Use Spec Builder
  • 48. @alexsotob REST-assured Request Specification .get("http://example.com/{composer}", "Ludwig van Beethoven") RequestSpecBuilder builder = new RequestSpecBuilder(); builder.setBaseUri("http://example.com"); given().spec(builder.build())... 21 Use domain directly Use Spec Builder Reuse Everywhere
  • 49. @alexsotob REST-assured Auth given().auth().oauth2(accessToken).when()... given().auth().form("John", "Doe", springSecurity().withCsrfFieldName("_csrf")).when()... given().auth().basic("username", "password").when()... 22
  • 50. @alexsotob Custom Parsers Not just JSON and XML SSL Support .relaxedHTTPSValidation() Filters Input/Output modification JSON Schema Validation Content not Important More Features of Rest-Assured 23
  • 52. @alexsotob Network Down Service Down Limits on API Component Not in Control Micro-Services Dependencies Hell Problems with Services 25
  • 53. @alexsotob Mock Http Component Stub/Fake Http Server Service Virtualization Possible Solutions 26
  • 56. @alexsotob Service Virtualization Capture Mode 28 Service A External Network Service B Scripts Proxy
  • 57. @alexsotob Service Virtualization Capture Mode 28 Service A External Network Service B Scripts Proxy
  • 58. @alexsotob Service Virtualization Capture Mode 28 Service A External Network Service B Scripts Proxy
  • 59. @alexsotob Service Virtualization Capture Mode 28 Service A External Network Service B Scripts Proxy
  • 60. @alexsotob Service Virtualization Capture Mode 28 Service A External Network Service B Scripts Proxy
  • 61. @alexsotob Service Virtualization Capture Mode 28 Service A External Network Service B Scripts Proxy
  • 62. @alexsotob Service Virtualization Simulate Mode 29 Service A External Network Service B Scripts Proxy
  • 63. @alexsotob Service Virtualization Simulate Mode 29 Service A External Network Service B Scripts Proxy
  • 64. @alexsotob Service Virtualization Simulate Mode 29 Service A External Network Service B Scripts Proxy
  • 65. @alexsotob Service Virtualization Simulate Mode 29 Service A External Network Service B Scripts Proxy
  • 66. @alexsotob Service Virtualization Simulate Mode 29 Service A External Network Service B Scripts Proxy
  • 68. @alexsotob Hoverfly Example @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inCaptureOrSimulationMode("getcomposers.json"); @Test public void should_get_composers_from_composers_microservice() { // Given: ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081); // When: Composer composer = composersGateway.getComposer("Ludwig van Beethoven"); // Then: assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven"); } 31
  • 69. @alexsotob Hoverfly Example @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inCaptureOrSimulationMode("getcomposers.json"); @Test public void should_get_composers_from_composers_microservice() { // Given: ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081); // When: Composer composer = composersGateway.getComposer("Ludwig van Beethoven"); // Then: assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven"); } 31 Start Hoverfly
  • 70. @alexsotob Hoverfly Example @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inCaptureOrSimulationMode("getcomposers.json"); @Test public void should_get_composers_from_composers_microservice() { // Given: ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081); // When: Composer composer = composersGateway.getComposer("Ludwig van Beethoven"); // Then: assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven"); } 31 Start Hoverfly Use Real Host
  • 71. @alexsotob Hoverfly Example @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inCaptureOrSimulationMode("getcomposers.json"); @Test public void should_get_composers_from_composers_microservice() { // Given: ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081); // When: Composer composer = composersGateway.getComposer("Ludwig van Beethoven"); // Then: assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven"); } 31 Start Hoverfly Use Real Host Get Data from Real
  • 72. @alexsotob Hoverfly Example @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inCaptureOrSimulationMode("getcomposers.json"); @Test public void should_get_composers_from_composers_microservice() { // Given: ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081); // When: Composer composer = composersGateway.getComposer("Ludwig van Beethoven"); // Then: assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven"); } 31 Start Hoverfly Use Real Host Get Data from Real { "data" : { "pairs" : [{ "request" : { "path" : "/Ludwig van Beethoven", "method" : "GET", "destination" : “operas.com:8081", ... } "response" : { "status" : 200, "body" : "{"name":"Ludwig van Beethoven",}", "encodedBody" : false, "headers" : { "Connection" : [ "keep-alive" ], ... } } } }
  • 73. @alexsotob Hoverfly Example @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inCaptureOrSimulationMode("getcomposers.json"); @Test public void should_get_composers_from_composers_microservice() { // Given: ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081); // When: Composer composer = composersGateway.getComposer("Ludwig van Beethoven"); // Then: assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven"); } 31 Start Hoverfly Use Real Host Get Data from Real
  • 74. @alexsotob Hoverfly Example @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inCaptureOrSimulationMode("getcomposers.json"); @Test public void should_get_composers_from_composers_microservice() { // Given: ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081); // When: Composer composer = composersGateway.getComposer("Ludwig van Beethoven"); // Then: assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven"); } 31 Start Hoverfly Use Real Host Get Data from Proxy
  • 77. @alexsotob Testing Containers docker build -t myorg/myservice:1.0.0 . docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0 docker-compose up mvn clean test docker-compose stop 33
  • 78. @alexsotob Testing Containers docker build -t myorg/myservice:1.0.0 . docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0 docker-compose up mvn clean test docker-compose stop 33 Docker Run
  • 79. @alexsotob Testing Containers docker build -t myorg/myservice:1.0.0 . docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0 docker-compose up mvn clean test docker-compose stop 33 Docker Run Docker Compose Run
  • 80. @alexsotob Testing Containers docker build -t myorg/myservice:1.0.0 . docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0 docker-compose up mvn clean test docker-compose stop 33 Docker Run Docker Compose Run Run tests
  • 81. @alexsotob Testing Containers docker build -t myorg/myservice:1.0.0 . docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0 docker-compose up mvn clean test docker-compose stop 33 Docker Run Docker Compose Run Run tests Stop Docker Containers
  • 83. @alexsotob Arquillian Cube Example @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource @DockerUrl(containerName = "helloworld", exposedPort = 8080) RequestSpecBuilder requestSpecBuilder; @Test public void should_receive_ok_message() { RestAssured .given() .spec(requestSpecBuilder.build()) .when() .get() .then() .assertThat().body("status", equalTo("OK")); } } 35
  • 84. @alexsotob Arquillian Cube Example @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource @DockerUrl(containerName = "helloworld", exposedPort = 8080) RequestSpecBuilder requestSpecBuilder; @Test public void should_receive_ok_message() { RestAssured .given() .spec(requestSpecBuilder.build()) .when() .get() .then() .assertThat().body("status", equalTo("OK")); } } 35 Arquillian Runner
  • 85. @alexsotob Arquillian Cube Example @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource @DockerUrl(containerName = "helloworld", exposedPort = 8080) RequestSpecBuilder requestSpecBuilder; @Test public void should_receive_ok_message() { RestAssured .given() .spec(requestSpecBuilder.build()) .when() .get() .then() .assertThat().body("status", equalTo("OK")); } } 35 Arquillian Runner REST-Assured Integration Environment Resolver
  • 86. @alexsotob Arquillian Cube Example @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource @DockerUrl(containerName = "helloworld", exposedPort = 8080) RequestSpecBuilder requestSpecBuilder; @Test public void should_receive_ok_message() { RestAssured .given() .spec(requestSpecBuilder.build()) .when() .get() .then() .assertThat().body("status", equalTo("OK")); } } 35 Arquillian Runner REST-Assured Integration Environment Resolver Normal REST-Assured Call
  • 87. @alexsotob Arquillian Cube Example @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource @DockerUrl(containerName = "helloworld", exposedPort = 8080) RequestSpecBuilder requestSpecBuilder; @Test public void should_receive_ok_message() { RestAssured .given() .spec(requestSpecBuilder.build()) .when() .get() .then() .assertThat().body("status", equalTo("OK")); } } 35 Arquillian Runner REST-Assured Integration Environment Resolver Normal REST-Assured Call helloworld: image: jonmorehouse/ping-pong ports: - "8080:8080" src/test/docker/docker-compose.yml
  • 88. @alexsotob Arquillian Cube DSL @RunWith(SpringRunner.class) @SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class) public class PingPongSpringBootTest { @ClassRule public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6") .withPortBinding(6379); @Autowired TestRestTemplate restTemplate; @Test public void should_get_data_from_redis() { } 36
  • 89. @alexsotob Arquillian Cube DSL @RunWith(SpringRunner.class) @SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class) public class PingPongSpringBootTest { @ClassRule public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6") .withPortBinding(6379); @Autowired TestRestTemplate restTemplate; @Test public void should_get_data_from_redis() { } 36 Spring Boot Test
  • 90. @alexsotob Arquillian Cube DSL @RunWith(SpringRunner.class) @SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class) public class PingPongSpringBootTest { @ClassRule public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6") .withPortBinding(6379); @Autowired TestRestTemplate restTemplate; @Test public void should_get_data_from_redis() { } 36 Spring Boot Test Custom Initializer
  • 91. @alexsotob Arquillian Cube DSL @RunWith(SpringRunner.class) @SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class) public class PingPongSpringBootTest { @ClassRule public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6") .withPortBinding(6379); @Autowired TestRestTemplate restTemplate; @Test public void should_get_data_from_redis() { } 36 Spring Boot Test Custom Initializer Container Definition
  • 92. @alexsotob Arquillian Cube DSL @RunWith(SpringRunner.class) @SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class) public class PingPongSpringBootTest { @ClassRule public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6") .withPortBinding(6379); @Autowired TestRestTemplate restTemplate; @Test public void should_get_data_from_redis() { } 36 Spring Boot Test Custom Initializer Container Definition public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) { EnvironmentTestUtils.addEnvironment("testcontainers", configurableApplicationContext.getEnvironment(), "spring.redis.host=" + redis.getIpAddress(), "spring.redis.port=" + redis.getBindPort(6379) );
  • 93. @alexsotob Arquillian Cube DSL @RunWith(SpringRunner.class) @SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class) public class PingPongSpringBootTest { @ClassRule public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6") .withPortBinding(6379); @Autowired TestRestTemplate restTemplate; @Test public void should_get_data_from_redis() { } 36 Spring Boot Test Custom Initializer Container Definition public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) { EnvironmentTestUtils.addEnvironment("testcontainers", configurableApplicationContext.getEnvironment(), "spring.redis.host=" + redis.getIpAddress(), "spring.redis.port=" + redis.getBindPort(6379) ); Sets Container Environment
  • 94. @alexsotob Arquillian Cube K8S/OpenShift @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource KubernetesClient client; @Named("hello-world-service") @PortForward @ArquillianResource URL url; @Test public void testRunningPodStaysUp() throws Exception { assertThat(client).deployments().pods().isPodReadyForPeriod(); } } 37
  • 95. @alexsotob Arquillian Cube K8S/OpenShift @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource KubernetesClient client; @Named("hello-world-service") @PortForward @ArquillianResource URL url; @Test public void testRunningPodStaysUp() throws Exception { assertThat(client).deployments().pods().isPodReadyForPeriod(); } } 37 Kubernetes Client
  • 96. @alexsotob Arquillian Cube K8S/OpenShift @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource KubernetesClient client; @Named("hello-world-service") @PortForward @ArquillianResource URL url; @Test public void testRunningPodStaysUp() throws Exception { assertThat(client).deployments().pods().isPodReadyForPeriod(); } } 37 Kubernetes Client URL to Access Service
  • 97. @alexsotob Arquillian Cube K8S/OpenShift @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource KubernetesClient client; @Named("hello-world-service") @PortForward @ArquillianResource URL url; @Test public void testRunningPodStaysUp() throws Exception { assertThat(client).deployments().pods().isPodReadyForPeriod(); } } 37 Kubernetes Client URL to Access Service AssertJ Custom Assertions
  • 102. @alexsotob Smart Testing Maven Extension curl -sSL https://git.io/v5jy6 | bash 40
  • 103. @alexsotob Smart Testing Maven Extension curl -sSL https://git.io/v5jy6 | bash 40 Installs extension
  • 104. @alexsotob Smart Testing Maven Extension curl -sSL https://git.io/v5jy6 | bash 40 Installs extension mvn clean test -Dsmart.testing="new, changed, affected"
  • 105. @alexsotob Smart Testing Maven Extension curl -sSL https://git.io/v5jy6 | bash 40 Installs extension mvn clean test -Dsmart.testing="new, changed, affected" Runs ONLY new, changed and prod related tests
  • 106. @alexsotob Smart Testing Maven Extension curl -sSL https://git.io/v5jy6 | bash 40 Installs extension mvn clean test -Dsmart.testing="new, changed, affected" Runs ONLY new, changed and prod related tests mvn clean test -Dsmart.testing.mode=ordering -Dsmart.testing="new, changed, affected”
  • 107. @alexsotob Smart Testing Maven Extension curl -sSL https://git.io/v5jy6 | bash 40 Installs extension mvn clean test -Dsmart.testing="new, changed, affected" Runs ONLY new, changed and prod related tests mvn clean test -Dsmart.testing.mode=ordering -Dsmart.testing="new, changed, affected” Prioritize new, changed and prod related tests
  • 109. @alexsotob From Low to High Level Unit, Component, Integration, Deployment Not Just for Micro-Services Same can be reused for monolithic Improves Readability Tests are meant to be read Conclusions 42 Deployment Velocity From week to several times per day