TESTING LIBRARIES
FOR FUN & PROFIT
BEWARE: INCREASED PRODUCTIVITY AHEAD@IXCHELRUIZ — PRINCIPAL CONSULTANT
TRIVADIS AG
ixchelruiz
AIM
Rest APIs
Fake Servers
Fake Clients
Parameterized Tests
Spy, Mock, Stub
ixchelruiz
Open Source
ixchelruiz
ixchelruiz
REST API
ixchelruiz
WHAT? WHY? WHO? WHEN?
REpresentational State Transfer.
“Architectural style for distributed hypermedia
systems, as it has been developed to represent the
model for how the modern Web should work. REST
provides a set of architectural constraints that,
when applied as a whole, emphasizes scalability of
component interactions, generality of interfaces,
independent deployment of components, and
intermediary components to reduce interaction
latency, enforce security, and encapsulate legacy
systems”
ixchelruiz
WHAT? WHY? WHO? WHEN?
REpresentational State Transfer.
“Architectural style for distributed hypermedia
systems, as it has been developed to represent the
model for how the modern Web should work. REST
provides a set of architectural constraints that,
when applied as a whole, emphasizes scalability of
component interactions, generality of interfaces,
independent deployment of components, and
intermediary components to reduce interaction
latency, enforce security, and encapsulate legacy
systems”
ixchelruiz
WHAT? WHY? WHO? WHEN?
REpresentational State Transfer.
“Architectural style for distributed hypermedia
systems, as it has been developed to represent the
model for how the modern Web should work. REST
provides a set of architectural constraints that,
when applied as a whole, emphasizes scalability of
component interactions, generality of interfaces,
independent deployment of components, and
intermediary components to reduce interaction
latency, enforce security, and encapsulate legacy
systems”
— Roy Thomas Fielding
https://www.ics.uci.edu/~fielding/pubs/dissertation/web_arch_domain.htm
ixchelruiz
WHAT? WHO? WHY? WHEN?
REpresentational State Transfer.
“Architectural style for distributed hypermedia
systems, as it has been developed to represent the
model for how the modern Web should work. REST
provides a set of architectural constraints that,
when applied as a whole, emphasizes scalability of
component interactions, generality of interfaces,
independent deployment of components, and
intermediary components to reduce interaction
latency, enforce security, and encapsulate legacy
systems”
— Roy Thomas Fielding (2000)
https://www.ics.uci.edu/~fielding/pubs/dissertation/web_arch_domain.htm
ixchelruiz
STATE OF AFFAIRS
Heterogeneous collection of
terminals, workstations, servers
and supercomputers.
ixchelruiz
STATE OF AFFAIRS
Heterogeneous collection of
terminals, workstations, servers
and supercomputers.
ixchelruiz
STATE OF AFFAIRS
Evolution of REST APIs
(Model, Documentation,
Implementation)
ixchelruiz
OPEN API 3.0OAI/OPENAPI-SPECIFICATION
ixchelruiz
WHAT? WHY? WHO? WHEN?
“Define a standard, language-agnostic interface to
REST APIs which allows both humans and
computers to discover and understand the
capabilities of the service without access to source
code, documentation, or through network traffic
inspection. When properly defined via OpenAPI, a
consumer can understand and interact with the
remote service with a minimal amount of
implementation logic.”
ixchelruiz
WHAT? WHY? WHO? WHEN?
“Define a standard, language-agnostic interface to
REST APIs which allows both humans and
computers to discover and understand the
capabilities of the service without access to source
code, documentation, or through network traffic
inspection. When properly defined via OpenAPI, a
consumer can understand and interact with the
remote service with a minimal amount of
implementation logic.”
#vendorNeutral #portable #open #specification #technical
#metadata
ixchelruiz
WHAT? WHY? WHO? WHEN?
“Define a standard, language-agnostic interface to
REST APIs which allows both humans and
computers to discover and understand the
capabilities of the service without access to source
code, documentation, or through network traffic
inspection. When properly defined via OpenAPI, a
consumer can understand and interact with the
remote service with a minimal amount of
implementation logic.”
#vendorNeutral #portable #open #specification #technical
#metadata
— OpenApi Initiative
ixchelruiz
WHAT? WHO? WHY? WHEN?
“Define a standard, language-agnostic interface to
REST APIs which allows both humans and
computers to discover and understand the
capabilities of the service without access to source
code, documentation, or through network traffic
inspection. When properly defined via OpenAPI, a
consumer can understand and interact with the
remote service with a minimal amount of
implementation logic.”
#vendorNeutral #portable #open #specification #technical
#metadata
— OpenApi Initiative (Jul 26, 2017)
ixchelruiz
OPEN API INITIATIVE
ixchelruiz
WHAT? WHY? WHO? WHEN?
“The OpenAPI Initiative (OAI) was created by a
consortium of forward-looking industry experts
who recognize the immense value of standardizing
on how REST APIs are described. Provides an open
source, technical community, within which industry
participants may easily contribute to building a
vendor-neutral, portable and open specification for
providing technical metadata for REST APIs. The
OAI is a collaborative project under the guidance of
the The Linux Foundation”
ixchelruiz
WHAT? WHY? WHO? WHEN?
“The OpenAPI Initiative (OAI) was created by a
consortium of forward-looking industry experts
who recognize the immense value of standardizing
on how REST APIs are described. Provides an open
source, technical community, within which
industry participants may easily contribute to
building a vendor-neutral, portable and open
specification for providing technical metadata for
REST APIs. The OAI is a collaborative project under
the guidance of the The Linux Foundation”
ixchelruiz
WHAT? WHY? WHO? WHEN?
ixchelruiz
WHAT? WHY? WHO? WHEN?
2015
ixchelruiz
Tools that support OpenApi 3.0
http://openapi.tools
ixchelruiz
PROFIT
OPEN API
INITIATIVE & SPEC
ixchelruiz
OPEN API 3.0
“Define a standard, language-agnostic interface to
REST APIs which allows both humans and
computers to discover and understand the
capabilities of the service without access to source
code, documentation, or through network traffic
inspection. When properly defined via OpenAPI,
a consumer can understand and interact with the
remote service with a minimal amount of
implementation logic.”
— Open API Initiative
ixchelruiz
OPEN API 3.0
“Define a standard, language-agnostic interface to
REST APIs which allows both humans and
computers to discover and understand the
capabilities of the service without access to source
code, documentation, or through network traffic
inspection. When properly defined via OpenAPI,
a consumer can understand and interact with the
remote service with a minimal amount of
implementation logic.”
— Open API Initiative
ixchelruiz
REST API
SPEC
ixchelruiz
DEMO
ixchelruiz
https://editor.swagger.io
ixchelruiz
SWAGGER
EDITOR
ixchelruiz
https://github.com/swagger-api/swagger-editor
ixchelruiz
ixchelruiz
SWAGGER
CODEGEN
ixchelruiz
https://github.com/swagger-api/swagger-codegen
ixchelruiz
https://github.com/swagger-api/swagger-codegen/wiki/Server-stub-generator-HOWTO
ixchelruiz
WIREMOCK
ixchelruiz
http://wiremock.org
ixchelruiz
DEMO
ixchelruiz
ixchelruiz
Standalone
ixchelruiz
Configure ports
$ java -jar wiremock-standalone-2.19.0.jar -- port 9090
Record & Map
$ java -jar wiremock-standalone-2.19.0.jar --proxy-all http://
wiremock.org —record-mappings
Review the mappings
http://localhost:8080/__admin/
Replay
$ java -jar wiremock-standalone-2.19.0.jar
ixchelruiz
Adding mappings (text/plain)
$ curl --verbose --data '{
"request": { "url": "/get/this", "method": "GET" },
"response": {
"status": 200, "body": "Here it is!n",
"headers": {"Content-Type": "text/plain"}
}}' http://localhost:8080/__admin/mappings/new
Test the new mapping
$ curl http://localhost:8080/get/this
ixchelruiz
Adding mappings (json)
$ curl --verbose --data '{
"request": { "url": "/get/json", "method": "GET" },
"response": {
"status": 200,
"jsonBody": {"unconferences":["jCrete","jAlba","jTaco"]},
"headers": {"Content-Type": "application/json"}
}}' http://localhost:8080/__admin/mappings/new
Test the new mapping
$ curl http://localhost:8080/get/json
ixchelruiz
Adding patterns in URLs
$ curl --verbose --data '{
"request": {
"urlPathPattern": "/get/([a-z]*)/test", "method": "GET" },
"response": {
"status": 200,
"body": "Here it is with pattern"
}}' http://localhost:8080/__admin/mappings/new
Test the new mapping
$ curl http://localhost:8080/get/whatever/test
ixchelruiz
Using patterns is the body
$ curl --verbose --data '{
"request": { "method": "POST", "url": "/post/bodyPattern",
"bodyPatterns" : [ {
"equalToJson" : { "total_results": 4 } }] },
"response": {
"status": 200, "body": "The body pattern was matched"
}}' http://localhost:8080/__admin/mappings/new
Test the new mapping
$ curl --verbose --data '{
"total_results":4}'
http://localhost:8080/post/bodyPattern
ixchelruiz
http://wiremock.org/docs/request-matching/
ixchelruiz
Delaying responses
$curl --verbose --data '{
"request": { "method": "GET", "url": "/get/delayed" },
"response": {
"status": 200,
"fixedDelayMilliseconds": 2000
}}' http://localhost:8080/__admin/mappings/new
Test the new mapping
$ curl http://localhost:8080/get/delayed
ixchelruiz
Simulating Fault
$curl --verbose --data '{
"request": {
"method": "GET", "url": "/get/fault"},
"response": {
"fault": "MALFORMED_RESPONSE_CHUNK"
}}' http://localhost:8080/__admin/mappings/new
Test the new mapping
$ curl http://localhost:8080/get/fault
ixchelruiz
Verifying number of requests
$ curl -X POST --header 'Content-Type: application/json' 
--header 'Accept: application/json' 
-d '{"url":"/get/delayed"}' 'http://localhost:8080/__admin/
requests/count'
Admin reference
http://localhost:8080/__admin/docs/
Reset
http://localhost:8080/__admin/reset/
ixchelruiz
https://chrome.google.com/webstore/detail/wiremock-extension/ikiaofdpbmofgmlhajfnhdjelkleljbl
ixchelruiz
REST
ASSURE
ixchelruiz
http://rest-assured.io
ixchelruiz
ixchelruiz
EXAMPLES
ixchelruiz
import static io.restassured.RestAssured.given;

import static io.restassured.RestAssured.get;
import static java.util.Arrays.asList;
import static org.hamcrest.Matchers.equalTo;
import org.junit.Test;
@Test
public void initial_data_is_loaded() {

given().
port(4567).
when().
get("/todos").
then().
body("todos.description", equalTo(asList(“Add Javadoc")));

}
@Test
public void formParamAreTreatedAsQueryParamsForGetRequests(){
given().
formParam("firstName", "John").
formParam("lastName", "Doe").
when().
get("/greet").
then().
body("greeting", equalTo("Greetings John Doe"));
}
ixchelruiz
import static io.restassured.RestAssured.given;
import static io.restassured.RestAssured.expect;
import static org.hamcrest.Matchers.equalTo;
import org.junit.Test;
@Test
public void newSyntaxWithCorrectStatusLineUsingStringMatching() {
expect().
statusLine("HTTP/1.1 200 OK").and().body("lotto.lottoId", equalTo(5)).
when().
get("/lotto");
}
@Test
public void requestSpecificationAllowsSpecifyingCookie() {
given().
cookie("username", “John”).then().
expect().
body(equalTo("username")).when().get("/cookie");
}
@Test
public void given_when_then_using_i18n_works() {
get(“/i18n").
then().
assertThat().body("ön", equalTo("Är ån"));
}
ixchelruiz
SPOCK
ixchelruiz
http://spockframework.org
ixchelruiz
ixchelruiz
EXAMPLES
ixchelruiz
@spock.lang.Unroll
class SampleControllerSpec extends spock.lang.Specification {
def "Invoke say hello with #input results in #output"() {
given:
SampleController controller = new SampleController()
controller.model = new SampleModel()
controller.service = Mock(SampleService) {
sayHello(input) >> output
}
when:
controller.model.input = input controller.sayHello()
then:
controller.model.output == output
where:
input << ['', 'Test']
output << ['Howdy, stranger!', 'Hello Test']
}
}
ixchelruiz
@spock.lang.Unroll
class SampleControllerSpec extends spock.lang.Specification {
def "Invoke say hello with #input results in #output"() {
given:
SampleController controller = new SampleController()
controller.model = new SampleModel()
controller.service = Mock(SampleService) {
sayHello(input) >> output
}
when:
controller.model.input = input
controller.sayHello()
then:
controller.model.output == output
where:
input | output
'' | 'Test'
'Howdy, stranger!' | 'Hello Test'
}
}
ixchelruiz
THANK YOU
FEEDBACK?

Testing libraries for fun & profit. Beware: Increased productivity ahead

  • 1.
    TESTING LIBRARIES FOR FUN& PROFIT BEWARE: INCREASED PRODUCTIVITY AHEAD@IXCHELRUIZ — PRINCIPAL CONSULTANT TRIVADIS AG
  • 2.
    ixchelruiz AIM Rest APIs Fake Servers FakeClients Parameterized Tests Spy, Mock, Stub
  • 3.
  • 4.
  • 5.
  • 6.
    ixchelruiz WHAT? WHY? WHO?WHEN? REpresentational State Transfer. “Architectural style for distributed hypermedia systems, as it has been developed to represent the model for how the modern Web should work. REST provides a set of architectural constraints that, when applied as a whole, emphasizes scalability of component interactions, generality of interfaces, independent deployment of components, and intermediary components to reduce interaction latency, enforce security, and encapsulate legacy systems”
  • 7.
    ixchelruiz WHAT? WHY? WHO?WHEN? REpresentational State Transfer. “Architectural style for distributed hypermedia systems, as it has been developed to represent the model for how the modern Web should work. REST provides a set of architectural constraints that, when applied as a whole, emphasizes scalability of component interactions, generality of interfaces, independent deployment of components, and intermediary components to reduce interaction latency, enforce security, and encapsulate legacy systems”
  • 8.
    ixchelruiz WHAT? WHY? WHO?WHEN? REpresentational State Transfer. “Architectural style for distributed hypermedia systems, as it has been developed to represent the model for how the modern Web should work. REST provides a set of architectural constraints that, when applied as a whole, emphasizes scalability of component interactions, generality of interfaces, independent deployment of components, and intermediary components to reduce interaction latency, enforce security, and encapsulate legacy systems” — Roy Thomas Fielding https://www.ics.uci.edu/~fielding/pubs/dissertation/web_arch_domain.htm
  • 9.
    ixchelruiz WHAT? WHO? WHY?WHEN? REpresentational State Transfer. “Architectural style for distributed hypermedia systems, as it has been developed to represent the model for how the modern Web should work. REST provides a set of architectural constraints that, when applied as a whole, emphasizes scalability of component interactions, generality of interfaces, independent deployment of components, and intermediary components to reduce interaction latency, enforce security, and encapsulate legacy systems” — Roy Thomas Fielding (2000) https://www.ics.uci.edu/~fielding/pubs/dissertation/web_arch_domain.htm
  • 10.
    ixchelruiz STATE OF AFFAIRS Heterogeneouscollection of terminals, workstations, servers and supercomputers.
  • 11.
    ixchelruiz STATE OF AFFAIRS Heterogeneouscollection of terminals, workstations, servers and supercomputers.
  • 12.
    ixchelruiz STATE OF AFFAIRS Evolutionof REST APIs (Model, Documentation, Implementation)
  • 13.
  • 14.
    ixchelruiz WHAT? WHY? WHO?WHEN? “Define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via OpenAPI, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.”
  • 15.
    ixchelruiz WHAT? WHY? WHO?WHEN? “Define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via OpenAPI, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.” #vendorNeutral #portable #open #specification #technical #metadata
  • 16.
    ixchelruiz WHAT? WHY? WHO?WHEN? “Define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via OpenAPI, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.” #vendorNeutral #portable #open #specification #technical #metadata — OpenApi Initiative
  • 17.
    ixchelruiz WHAT? WHO? WHY?WHEN? “Define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via OpenAPI, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.” #vendorNeutral #portable #open #specification #technical #metadata — OpenApi Initiative (Jul 26, 2017)
  • 18.
  • 19.
    ixchelruiz WHAT? WHY? WHO?WHEN? “The OpenAPI Initiative (OAI) was created by a consortium of forward-looking industry experts who recognize the immense value of standardizing on how REST APIs are described. Provides an open source, technical community, within which industry participants may easily contribute to building a vendor-neutral, portable and open specification for providing technical metadata for REST APIs. The OAI is a collaborative project under the guidance of the The Linux Foundation”
  • 20.
    ixchelruiz WHAT? WHY? WHO?WHEN? “The OpenAPI Initiative (OAI) was created by a consortium of forward-looking industry experts who recognize the immense value of standardizing on how REST APIs are described. Provides an open source, technical community, within which industry participants may easily contribute to building a vendor-neutral, portable and open specification for providing technical metadata for REST APIs. The OAI is a collaborative project under the guidance of the The Linux Foundation”
  • 21.
  • 22.
  • 23.
    ixchelruiz Tools that supportOpenApi 3.0 http://openapi.tools
  • 24.
  • 25.
    ixchelruiz OPEN API 3.0 “Definea standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via OpenAPI, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.” — Open API Initiative
  • 26.
    ixchelruiz OPEN API 3.0 “Definea standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via OpenAPI, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.” — Open API Initiative
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
    ixchelruiz Configure ports $ java-jar wiremock-standalone-2.19.0.jar -- port 9090 Record & Map $ java -jar wiremock-standalone-2.19.0.jar --proxy-all http:// wiremock.org —record-mappings Review the mappings http://localhost:8080/__admin/ Replay $ java -jar wiremock-standalone-2.19.0.jar
  • 42.
    ixchelruiz Adding mappings (text/plain) $curl --verbose --data '{ "request": { "url": "/get/this", "method": "GET" }, "response": { "status": 200, "body": "Here it is!n", "headers": {"Content-Type": "text/plain"} }}' http://localhost:8080/__admin/mappings/new Test the new mapping $ curl http://localhost:8080/get/this
  • 43.
    ixchelruiz Adding mappings (json) $curl --verbose --data '{ "request": { "url": "/get/json", "method": "GET" }, "response": { "status": 200, "jsonBody": {"unconferences":["jCrete","jAlba","jTaco"]}, "headers": {"Content-Type": "application/json"} }}' http://localhost:8080/__admin/mappings/new Test the new mapping $ curl http://localhost:8080/get/json
  • 44.
    ixchelruiz Adding patterns inURLs $ curl --verbose --data '{ "request": { "urlPathPattern": "/get/([a-z]*)/test", "method": "GET" }, "response": { "status": 200, "body": "Here it is with pattern" }}' http://localhost:8080/__admin/mappings/new Test the new mapping $ curl http://localhost:8080/get/whatever/test
  • 45.
    ixchelruiz Using patterns isthe body $ curl --verbose --data '{ "request": { "method": "POST", "url": "/post/bodyPattern", "bodyPatterns" : [ { "equalToJson" : { "total_results": 4 } }] }, "response": { "status": 200, "body": "The body pattern was matched" }}' http://localhost:8080/__admin/mappings/new Test the new mapping $ curl --verbose --data '{ "total_results":4}' http://localhost:8080/post/bodyPattern
  • 46.
  • 47.
    ixchelruiz Delaying responses $curl --verbose--data '{ "request": { "method": "GET", "url": "/get/delayed" }, "response": { "status": 200, "fixedDelayMilliseconds": 2000 }}' http://localhost:8080/__admin/mappings/new Test the new mapping $ curl http://localhost:8080/get/delayed
  • 48.
    ixchelruiz Simulating Fault $curl --verbose--data '{ "request": { "method": "GET", "url": "/get/fault"}, "response": { "fault": "MALFORMED_RESPONSE_CHUNK" }}' http://localhost:8080/__admin/mappings/new Test the new mapping $ curl http://localhost:8080/get/fault
  • 49.
    ixchelruiz Verifying number ofrequests $ curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{"url":"/get/delayed"}' 'http://localhost:8080/__admin/ requests/count' Admin reference http://localhost:8080/__admin/docs/ Reset http://localhost:8080/__admin/reset/
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
    ixchelruiz import static io.restassured.RestAssured.given;
 importstatic io.restassured.RestAssured.get; import static java.util.Arrays.asList; import static org.hamcrest.Matchers.equalTo; import org.junit.Test; @Test public void initial_data_is_loaded() {
 given(). port(4567). when(). get("/todos"). then(). body("todos.description", equalTo(asList(“Add Javadoc")));
 } @Test public void formParamAreTreatedAsQueryParamsForGetRequests(){ given(). formParam("firstName", "John"). formParam("lastName", "Doe"). when(). get("/greet"). then(). body("greeting", equalTo("Greetings John Doe")); }
  • 56.
    ixchelruiz import static io.restassured.RestAssured.given; importstatic io.restassured.RestAssured.expect; import static org.hamcrest.Matchers.equalTo; import org.junit.Test; @Test public void newSyntaxWithCorrectStatusLineUsingStringMatching() { expect(). statusLine("HTTP/1.1 200 OK").and().body("lotto.lottoId", equalTo(5)). when(). get("/lotto"); } @Test public void requestSpecificationAllowsSpecifyingCookie() { given(). cookie("username", “John”).then(). expect(). body(equalTo("username")).when().get("/cookie"); } @Test public void given_when_then_using_i18n_works() { get(“/i18n"). then(). assertThat().body("ön", equalTo("Är ån")); }
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
    ixchelruiz @spock.lang.Unroll class SampleControllerSpec extendsspock.lang.Specification { def "Invoke say hello with #input results in #output"() { given: SampleController controller = new SampleController() controller.model = new SampleModel() controller.service = Mock(SampleService) { sayHello(input) >> output } when: controller.model.input = input controller.sayHello() then: controller.model.output == output where: input << ['', 'Test'] output << ['Howdy, stranger!', 'Hello Test'] } }
  • 62.
    ixchelruiz @spock.lang.Unroll class SampleControllerSpec extendsspock.lang.Specification { def "Invoke say hello with #input results in #output"() { given: SampleController controller = new SampleController() controller.model = new SampleModel() controller.service = Mock(SampleService) { sayHello(input) >> output } when: controller.model.input = input controller.sayHello() then: controller.model.output == output where: input | output '' | 'Test' 'Howdy, stranger!' | 'Hello Test' } }
  • 63.