It is normal sometimes we will face such situation: your implementation is ready however your downstream system is still unknown i.e. it has not been deployed, it has not been developed whatever in one word not-ready! What can you do to do an integration test? The answer is mock it.
We use mock server as a mock tool. A maven configuration is as follows:
<plugin>
                <groupId>org.mock-server</groupId>
                <artifactId>mockserver-maven-plugin</artifactId>
                <version>3.10.4</version>
                <configuration>
                    <skip>false</skip>
                    <serverPort>57333</serverPort>
                    <logLevel>ERROR</logLevel>
                    <pipeLogToConsole>true</pipeLogToConsole>
                </configuration>
                <executions>
                    <execution>
                        <iFold>start-mork-server</id>
                        <phase>clean</phase>
                        <goals>
                            <goal>start</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>stop-mock-server</id>
                        <phase>test</phase>
                        <goals>
                            <goal>stop</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Configuration:

Folder Structure:

The configuration is per each downstream system/service. It is a folder with one “service.json” file and resource files (in subfolders).
All paths in the “service.json” are relative to the parent folder of the “service.json”.

folder structure.png

Service configuration file:

The service configuration contains “provider” name and a list of “Interactions”.
Each “interaction” has

  1. “request” where some values are variables
  2. “response” with default response parameters
  3. “switch” – list of variables (from request) – OPTIONAL
  4. “responses” – a map, where the keys are made from the variables and expected variable values, while the map values are “response” objects, whose values override the default response properties. – OPTIONAL

The order is important. It allows to define a default response by setting the most generic request matching conditions at the end.

Schema:

{
  “title”: “Service”,
  “description”: “Mock service configuration”,
  “required”: [
    “provider”,
    “interactions”
  ],
  “additionalProperties”: false,
  “properties”: {
    “provider”: {
      “type”: “string”
    },
    “interactions”: {
      “type”: “array”,
      “items”: {
        “$ref”: “#/definitions/interaction”
      }
    }
  },
  “definitions”: {
    “props”: {
      “type”: “object”,
      “patternProperties”: {
        “.+”: {
          “type”: “string”,
          “pattern”: “(^\\$\\{[^/]+\\}$)|(^[^\\$]{1}.*$)”
        }
      },
      “additionalProperties”: false
    },
    “response”: {
      “type”: “object”,
      “properties”: {
        “status”: {
          “type”: “integer”
        },
        “headers”: {
          “$ref”: “#/definitions/props”
        },
        “body”: {
          “type”: “string”
        },
        “latency”: {
          “type”: “integer”
        }
      }
    },
    “interaction”: {
      “type”: “object”,
      “properties”: {
        “request”: {
          “type”: “object”,
          “required”: true,
          “properties”: {
            “method”: {
              “type”: “array”,
              “items”: {
                “type”: “string”
              }
            },
            “path”: {
              “type”: “string”
            },
            “query”: {
              “$ref”: “#/definitions/props”
            },
            “cookies”: {
              “$ref”: “#/definitions/props”
            },
            “headers”: {
              “$ref”: “#/definitions/props”
            },
            “body”: {
              “type”: “object”,
              “properties”: {
                “regex”: {
                  “type”: “string”,
                  “pattern”: “(^\\$\\{[^/]+\\}$)|(^[^\\$]{1}.*$)”
                },
                “json”: {}
              }
            }
          },
          “required”: [
            “method”,
            “path”
          ]
        },
        “response”: {
          “$ref”: “#/definitions/response”
        },
        “switch”: {
          “type”: “array”,
          “items”: {
            “type”: “string”
          }
        },
        “responses”: {
          “type”: “object”,
          “additionalProperties”: {
            “$ref”: “#/definitions/response”
          }
        }
      },
      “additionalProperties”: false
    }
  }
}

Switch:

The purpose of these feature is to make the configuration more compact and easier to read. Without switch the configuration would look like a request –> response map, where the request and response are concrete values.
With switch we can mark some parts of the request as variables and move the corresponding list of values (n-tuple) to a switch key.

switch.png

Sample:

{
“request”: {
“method”: [
“POST”
],
“path”: “/myserice/mypath1/mypath2”,
“body”: {
“regex”:”myId\”:\”[0-9]{10,}”
}
},
“response”: {
“status”: 422,
“latency”:500,
“headers”:{
“Content-type”:”application/json;charset=UTF-8″
},
“body”: “data/response_422.json”
}
}

This tells you when it goes to URL Path/myserice/mypath1/mypath2 with any TEN digits myId  then it will give you a response with content as data/response_422.json

Advertisements