testing for unicorns [imworld]
TRANSCRIPT
@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
@alexsotob
AssertJ Testimport 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 Testimport 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 Testimport 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 Testimport 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
@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
@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 PollingsFixed, Fibonacci, Iterative, Custom
Simple LibraryNo dependencies, No magic
Benefits of Awaitility
15
@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
@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 ParsersNot just JSON and XML
SSL Support.relaxedHTTPSValidation()
FiltersInput/Output modification
JSON Schema ValidationContent not Important
More Featuresof Rest-Assured
23
@alexsotob
Network Down
Service Down
Limits on API
Component Not in Control
Micro-Services Dependencies Hell
Problems with Services
25
@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
@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
@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
@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 Definitionpublic 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 Definitionpublic 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
@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
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
@alexsotob
From Low to High LevelUnit, Component, Integration, Deployment
Not Just for Micro-ServicesSame can be reused for monolithic
Improves ReadabilityTests are meant to be read
Conclusions
42
Deployment VelocityFrom week to several times per day