Slide 1

Slide 1 text

Creating and testing REST Creating and testing REST and Messaging contracts and Messaging contracts with Spring Cloud Contract with Spring Cloud Contract @olga_maciaszek Olga Maciaszek-Sharma 09.10.2018

Slide 2

Slide 2 text

Olga Maciaszek-Sharma Olga Maciaszek-Sharma @olga_maciaszek https:/ /github.com/OlgaMaciaszek https:/ /github.com/OlgaMaciaszek @ @olga_maciaszek olga_maciaszek

Slide 3

Slide 3 text

E2E Tests E2E Tests @olga_maciaszek

Slide 4

Slide 4 text

@olga_maciaszek Source: https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html Test Pyramid Test Pyramid

Slide 5

Slide 5 text

Microservices Microservices @olga_maciaszek

Slide 6

Slide 6 text

Fully Deployed Test Fully Deployed Test Environment Environment @olga_maciaszek Environment per Service Environment per Service One To Rule Them All One To Rule Them All

Slide 7

Slide 7 text

Deployment Deployment Coupling Coupling @olga_maciaszek

Slide 8

Slide 8 text

Failsafe Failsafe vs. vs. Safe To Fail Safe To Fail @olga_maciaszek

Slide 9

Slide 9 text

Circuit Breakers Circuit Breakers @olga_maciaszek

Slide 10

Slide 10 text

How many E2E? How many E2E? @olga_maciaszek

Slide 11

Slide 11 text

Stubbed Stubbed Environments Environments @olga_maciaszek

Slide 12

Slide 12 text

Invalid Stubs - REST Invalid Stubs - REST @olga_maciaszek { “request” : { “method”: “GET”, “url” : “/endpointX”, }, “response” : { “status” : 200 } { “request” : { “method”: “GET”, “url” : “/endpointY”, }, “response” : { “status” : 200 }

Slide 13

Slide 13 text

Invalid Stubs - Messaging Invalid Stubs - Messaging @olga_maciaszek topic: foo class Product { int productId String productName } topic: bar class Product { int productId String productName } topic: foo class Product { int id String productName }

Slide 14

Slide 14 text

Stubbed Environments Stubbed Environments @olga_maciaszek Outdated Stubs Outdated Stubs

Slide 15

Slide 15 text

Contracts Contracts @olga_maciaszek Monitoring Monitoring Alerting Alerting Logging Logging Unit Tests Unit Tests

Slide 16

Slide 16 text

Input A ==> Output B Input A ==> Output B @olga_maciaszek Contracts Contracts [Consumer] [Contract] [Producer]

Slide 17

Slide 17 text

Consumer-Driven Contracts Consumer-Driven Contracts https://martinfowler.com/articles/consum erDrivenContracts.html @olga_maciaszek

Slide 18

Slide 18 text

Contract Tests Contract Tests https://martinfowler.com/bliki/ContractTest.html @olga_maciaszek

Slide 19

Slide 19 text

Spring Cloud Contract Spring Cloud Contract https://cloud.spring.io/spring-cloud-contract/ @olga_maciaszek

Slide 20

Slide 20 text

SCC Flow SCC Flow @olga_maciaszek

Slide 21

Slide 21 text

SCC Flow SCC Flow @olga_maciaszek

Slide 22

Slide 22 text

Contracts Contracts package contracts org.springframework.cloud.contract.spec.Contract.make { request { method 'PUT' url '/fraudcheck' body([ "client.id": $(regex('[0-9]{10}')), loanAmount: 99999 ]) headers { contentType('application/json') } } response { status OK() body([ fraudCheckStatus: "FRAUD", "rejection.reason": "Amount too high" ]) headers { contentType('application/json') } } } @olga_maciaszek

Slide 23

Slide 23 text

Contracts Contracts request: method: PUT url: /fraudcheck body: "client.id": 1234567890 loanAmount: 99999 headers: Content-Type: application/json matchers: body: - path: $.['client.id'] type: by_regex value: "[0-9]{10}" response: status: 200 body: fraudCheckStatus: "FRAUD" "rejection.reason": "Amount too high" headers: Content-Type: application/json;charset=UTF-8 @olga_maciaszek

Slide 24

Slide 24 text

SCC Flow SCC Flow @olga_maciaszek

Slide 25

Slide 25 text

Gradle Setup - Producer Gradle Setup - Producer buildscript { repositories { mavenCentral() maven {url 'http://repo.spring.io/release'} } dependencies { classpath("org.springframework.cloud:spring-cloud-contract-gradle } } apply plugin: 'spring-cloud-contract' contracts { targetFramework = 'SPOCK' baseClassForTests = 'com.example.contractsdemo.FraudCheckTestBaseClass' } @olga_maciaszek

Slide 26

Slide 26 text

Contract Tests Contract Tests def validate_shouldMarkClientAsFraud() { given: def request = given() .header('Content-Type', 'application/vnd.fraud.v1+json') .body('{"clientId":"12345678902","loanAmount":99999}') when: def response = given().spec(request).put("/fraudcheck") then: response.statusCode == 200 response.header('Content-Type') == 'application/vnd.fraud.v1+json' and: DocumentContext parsedJson = JsonPath.parse(response.body.asString()) assertTassertThatJson(parsedJson).field("rejectionReason") .isEqualTo("Amount too high") assertThatJson(parsedJson).field("fraudCheckStatus").isEqualTo("FRAUD") } @olga_maciaszek

Slide 27

Slide 27 text

Stubs Stubs { "request": { "url": "/fraudcheck", "method": "PUT", "bodyPatterns": [ { "matchesJsonPath": "$[?(@.loanAmount == 99999)]" }, { "matchesJsonPath": "$[?(@.clientId == '12345678902')]" } ], "headers": { "Content-Type": { "equalTo": "application/vnd.fraud.v1+json" } } }, "response": { "status": 200, "body": "{\"fraudCheckStatus\":\"FRAUD\", \"rejectionReason\":\"Amount too high\"}", "headers": { "Content-Type": "application/vnd.fraud.v1+json" } } } @olga_maciaszek

Slide 28

Slide 28 text

SCC Flow SCC Flow @olga_maciaszek

Slide 29

Slide 29 text

SCC Flow SCC Flow @olga_maciaszek

Slide 30

Slide 30 text

Gradle Setup - Consumer Gradle Setup - Consumer dependencies { testCompile('org.springframework.cloud:spring-cloud-starter-contract-stub-runner') } @olga_maciaszek

Slide 31

Slide 31 text

Using Stubs Using Stubs @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment=WebEnvironment.NONE) @AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL) public class LoanApplicationServiceTests { ... } @olga_maciaszek @StubRunnerPort

Slide 32

Slide 32 text

Using Stubs Using Stubs stubrunner: repositoryRoot: classpath:m2repo/repository/ ids: - org.springframework.cloud.contract.verifier.stubs:loanIssuance - org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer - org.springframework.cloud.contract.verifier.stubs:bootService stubs-mode: remote @olga_maciaszek @ContextConfiguration(classes = Config, loader = SpringBootContextLoader) @SpringBootTest(properties = [" stubrunner.cloud.enabled=false"]) @AutoConfigureStubRunner @ActiveProfiles("test") class StubRunnerConfigurationSpec extends Specification { @Autowired StubFinder stubFinder def 'should start WireMock servers'() { expect: 'WireMocks are running' stubFinder.findStubUrl('org.verifier.stubs', 'loanIssuance') != null }

Slide 33

Slide 33 text

Using Stubs Using Stubs @Rule public StubRunnerRule rule = new StubRunnerRule() .downloadStub("com.example","fraud-service") .stubsMode(StubRunnerProperties.StubsMode.LOCAL) .withStubPerConsumer(true) .withConsumerName("loan-service"); int fraudServicePort = rule.findStubUrl("fraud-service").getPort() @olga_maciaszek

Slide 34

Slide 34 text

Code Demo Code Demo @olga_maciaszek

Slide 35

Slide 35 text

Messaging Contracts Messaging Contracts def contractDsl = Contract.make { label 'some_label' input { messageFrom('inputQueue') messageBody([ bookName: 'foo' ]) messageHeaders { header('sample', 'header') } } outputMessage { sentTo('outputQueue') body([ bookName: 'foo' ]) headers { header('BOOK-NAME', 'foo') } } } @olga_maciaszek

Slide 36

Slide 36 text

Messaging Contract Tests Messaging Contract Tests given: ContractVerifierMessage inputMessage = contractVerifierMessaging.create( '''{"bookName":"foo"}''', ['sample': 'header'] ) when: contractVerifierMessaging.send(inputMessage, 'inputQueue') then: ContractVerifierMessage response = contractVerifierMessaging .receive('outputQueue') assert response != null response.getHeader('BOOK-NAME')?.toString() == 'foo' and: DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper .writeValueAsString(response.payload)) assertThatJson(parsedJson).field("bookName").isEqualTo("foo") @olga_maciaszek

Slide 37

Slide 37 text

Messaging Client-Side Test Messaging Client-Side Test given: messaging.send(new BookReturned('foo'), [sample: 'header'], 'input') when: Message> receivedMessage = messaging.receive('outputTest') then: receivedMessage != null assertJsons(receivedMessage.payload) receivedMessage.headers.get('BOOK-NAME') == 'foo' @olga_maciaszek

Slide 38

Slide 38 text

Code Demo Code Demo @olga_maciaszek

Slide 39

Slide 39 text

Public API Public API Spring Rest Docs Spring Rest Docs MockMvc Tests -> REST Docs, Stubs, Contracts @olga_maciaszek

Slide 40

Slide 40 text

Other Technologies Other Technologies mvn spring-cloud-contract:run -Dstubs="org.springframework:gs-rest-service" Docs @olga_maciaszek

Slide 41

Slide 41 text

Other Technologies Other Technologies @olga_maciaszek Docker Docker

Slide 42

Slide 42 text

Generate Rest Docs Generate Rest Docs from Contracts from Contracts @olga_maciaszek

Slide 43

Slide 43 text

Contracts Scope Contracts Scope Skip Contracts for non- Skip Contracts for non- essential functionality essential functionality @olga_maciaszek

Slide 44

Slide 44 text

Contracts Scope Contracts Scope Skip multiple values Skip multiple values @olga_maciaszek

Slide 45

Slide 45 text

Skip Multiple Values Skip Multiple Values @olga_maciaszek request { method 'PUT' url '/fraudcheck' body([ "client.id": $(regex('[0-9]{10}')), "client.type" : "INDIVIDUAL" loanAmount: 99999 ]) headers { contentType('application/json') }} request { method 'PUT' url '/fraudcheck' body([ "client.id": $(regex('[0-9]{10}')), "client.type" : "BUSINESS" loanAmount: 99999 ]) headers { contentType('application/json') }}

Slide 46

Slide 46 text

Architecture TDD Architecture TDD @olga_maciaszek

Slide 47

Slide 47 text

Backwards Backwards Compatibility Check Compatibility Check Spring Cloud Pipelines Spring Cloud Pipelines @olga_maciaszek

Slide 48

Slide 48 text

Deferred Updates Deferred Updates @olga_maciaszek

Slide 49

Slide 49 text

Spring Cloud Contract at Spring Cloud Contract at Devskiller - case study Devskiller - case study blogpost blogpost @olga_maciaszek

Slide 50

Slide 50 text

Demo Code Links Demo Code Links https://github.com/OlgaMaciaszek/contracts-demo- producer https://github.com/OlgaMaciaszek/contracts-demo- consumer https://github.com/OlgaMaciaszek/scc-payment https://github.com/OlgaMaciaszek/scc-shop @olga_maciaszek

Slide 51

Slide 51 text

https:/ /github.com/OlgaMaciaszek https:/ /github.com/OlgaMaciaszek @ @olga_maciaszek olga_maciaszek Thank you Thank you