decoupling to accelerate web api testing
contract test VS e2e

decoupling to accelerate web api testing

introduction

when i entered any url into my browser, a http call will be made to a server to request for that particular resource. The request will be based on the http verb and the resource is the path which is part of the url.

From user point of view i will see only url which represents a machine/server at other side which will serve my request. Of course in reality, there are many things happen behind the scene. This bring us to the old concept and a very fundamental in programming/architecture: interface.

ada apa dengan interface

we always interact with interface and take it for granted. Nowdays everybody carries a smartphone. Where do you plug ur charger? there is a interface for that in the form of :

Article content
interface to get all the juice for your smartphone ( depending on which region )

The above is just simplification of how interface make our life easier. It abstract away all the complexity. As long i can get the 'juice' flowing into my smartphone, i dont care what magical things happen behind the scene. The interface provide a contract between the consumer ( my smartphone charger) and provider ( the power company ). So when you use browser, know that you browser is api consumer and some machine inside your browser url is the api provider.

its all about testing

in the world of connecting devices. How do you scope what need to be test or not? it is super hard question but someone need to address it. What are the boundaries of testing? what test strategy should we adopt? Do we test all the component involve ?

most popular choice and by default: lets do end to end testing.

unpopular choice and perhaps, radical: contract testing

In my mind, if i talk about web api testing my default choice would be falls to contract testing.

Article content
lets all agree on something so we can work independently.

painful scenario of api provider and api consumer

imagine a fictional scenario:

  • a monolith organization which provide financial product to customer. One of its line of business(lob) offer a loan rumah application
  • a dedicated team in the monolith organization help bring the busines capability to partner in partner's digital offering
  • partner can be any organization outside of the monolith organization which have a comercial contract agreement as outsourcer to the monolith organization.

bring me...pain

Article content
pain in naruto

lob have many intiative happening and they also have many partner line up.

partner have many initiative happening and they have many other organizations to work with in order to provide marvellous digital offering.

coordination between monolith org and the partner need to be set to minimum. A side by side coordination just too complex top it with expensive as well.

the dedicated team have to juggle with many lob and many partner.

imagine when we apply end to end testing ?

decoupling to the rescue

instead of doing end to end like this

partner -> system which we dedicated team handle -> lob

we go with

system which we dedicated team handle -> lob then partner -> system which we dedicated team handle

important aspect to understand is the seggregation between api provider and api consumer. We can move the perspective of our test scope so the assignment of api provider and api consumer change but it still adhere to the web api contract.

talk is cheap, show me the running program

I will be imagining myself as one of the member of dedicated team ( between partner and lob, imagine malcom in the middle)

Article content
malcom in the middle

Customer can go to our partner digital platform. They can choose our monolith organization financial product ( loan rumah ) then customer can submit from their digital platform. Customer will be notify when the loan status change.

important pre-requisite

we are about test the interface and not the functionality lies behind the interface. To make this more palatable

  • contract has been agreed between lob and our malcom the middle team
  • the lob team had executed the SIT and UAT. We going to curi their request response and brand it as stub mapping.

abide to the contract

openapi: 3.0.3
info:
  title: Mortgage AIP Loan API
  version: 1.0.0
  description: API for submitting customer information for approval in principle for home loan application.
paths:
  /mortgage/aip/loan:
    post:
      summary: Submit customer information for AIP home loan application
      requestBody:
        description: Loan request including customer information and callback URL
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoanRequest'
      responses:
        '202':
          description: Accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Loan application received, processing initiated."
                  referenceId:
                    type: string
                    example: "12345"
      callbacks:
        loanStatusCallback:
          '{$request.body#/callback}/mortgage/aip/loan/{$response.body#/referenceId}':
            post:
              summary: Callback for loan application status
              requestBody:
                description: Loan application status update
                required: true
                content:
                  application/json:
                    schema:
                      type: object
                      properties:
                        status:
                          type: string
                          enum: [approved, rejected, pending]
                        message:
                          type: string
              responses:
                '200':
                  description: Acknowledged

components:
  schemas:
    LoanRequest:
      type: object
      properties:
        customerInfo:
          $ref: '#/components/schemas/CustomerInfo'
        callback:
          type: string
          format: uri
          pattern: '^https?://.+'
      required:
        - customerInfo
        - callback

    CustomerInfo:
      type: object
      properties:
        customerId:
          type: string
        name:
          type: string
        income:
          type: number
        loanAmount:
          type: number
        propertyValue:
          type: number
      required:
        - customerId
        - name
        - income
        - loanAmount
        - propertyValue
        

this is openapi. Standard introduce to define web api. But normally this will be always be confuse with swagger.

make it replayable and configurable

The most straighforward thinking is by embedding the response in the application code. But you can guess the high cost of maintaining it over time. Its not wrong, improvement comes from maturity and maturity require time plus effort in learning implementation.

I will take different approach.

define our request response inside a configuration file

{
  "request": {
    "method": "POST",
    "url": "/mortgage/aip/loan",
    "bodyPatterns": [
      {
        "matchesJsonPath": "$[?(@.customerInfo.customerId)]"
      },
      {
        "matchesJsonPath": "$[?(@.customerInfo.name)]"
      },
      {
        "matchesJsonPath": "$[?(@.customerInfo.income)]"
      },
      {
        "matchesJsonPath": "$[?(@.customerInfo.loanAmount)]"
      },
      {
        "matchesJsonPath": "$[?(@.customerInfo.propertyValue)]"
      },
      {
        "matchesJsonPath": "$[?(@.callback)]"
      }
    ]
  },
  "response": {
    "status": 202,
    "jsonBody": {
      "message": "Loan application received, processing initiated.",
      "referenceId": "12345"
    },
    "headers": {
      "Content-Type": "application/json"
    }
  },
  "serveEventListeners": [
    {
      "name": "webhook",
      "parameters": {
        "method": "POST",
        "url": "http://localhost:8080/api/callback/mortgage/aip/loan/12345",
        "headers": {
          "Content-Type": "application/json"
        },
        "body": {
          "status": "approved",
          "message": "Your loan application has been approved."
        },
        "fixedDelayMilliseconds": 1000
      }
    }
  ]
}
        

As you can see we will map request to a response. Nothing fancy. This configuration fill will load by an application to serve request with its canned response.


Article content
request test the stub


Article content
request received, response return and follow by a callback













To view or add a comment, sign in

More articles by Faisal Pk

Others also viewed

Explore content categories