Why we need Mocking?
We are often in a need to create stubs or mocks when the API under test is not completely ready or we need to test the external systems without getting affected by any external environmental problems.
Requirements for our API service:
Our service has all the below specifications.
Endpoint URL (Base path and resource path)
Body
Query Parameters
Path Parameters
Headers
Our product type is courses and we can do below operations for shoppingcart service:
Create a shopping cart. (POST)
Get/Retrieve a shopping cart details. (GET)
Now let’s define the service requirements step by step.
Service URL
Base URL http://test.myshop.com
Base Path carts
Headers:
Content-Type application/json
Accept application/json
Version v1
Client Android
Authorization Bearer <token>
Create a Shopping Cart
Method: POST
Resource Path: No resource path required.
Example Request: POST /carts
Body:
Our shopping cart has customer and products attributes and they have their own attributes as shown below.
{
"customer":{
"id":"9879898787",
"firstName":"Neeraj",
"lastName":"Bakhtani",
"email":"myemailId@gmail.com"
},
"products":[
{
"description":"Rest API mocking using WireMock",
"type":"Course",
"productAttributes":[
{
"courseLenght":"5 hours",
"courseRating": "5 stars",
"courseCreationDate":"2021-01-14",
"courseLevel":"Advanced"
}
],
"price":{
"amount": 100.0,
"discount": 30.0,
"paymetType":"VISA CREDIT CARD",
"currency": "SGD"
}
}
]
}
Response:
{
"customer":{
"id":"9879898787",
"firstName":"Neeraj",
"lastName":"Bakhtani",
"email":"myemailId@gmail.com"
},
"products":[
{
"description":"Rest API mocking using WireMock",
"type":"Course",
"productAttributes":[
{
"courseLenght":"5 hours",
"courseRating": "5 stars",
"courseCreationDate":"2021-01-14",
"courseLevel":"Advanced"
}
],
"price":{
"amount": 100.0,
"discount": 30.0,
"paymetType":"VISA CREDIT CARD",
"currency": "SGD"
}
}
]
}
Get a Shopping Cart
Method: GET
Resource Path: {cartId}
Query Param: productCount (I added to distinguish 1 and 2 product mocking. Normally, we do not need this kind of QueryParams.)
Example Request: GET /carts/quil514c-9678-4a4b-b32d-550b7fc3cfb2?productCount=1
Response
{
"id": "quil514c-9678-4a4b-b32d-550b7fc3cfb2",
"customer": {
"id": "9879898787",
"firstName": "Neeraj",
"lastName": "Bakhtani",
"email": "myemailId@gmail.com"
},
"products": [
{
"id": "93b55282-334c-48b0-a8f7-a9d5eef9c4b9",
"description": "Rest API mocking using WireMock",
"type": "Course",
"productAttributes": [
{
"courseLenght": "5 hours",
"courseRating": "5 stars",
"courseCreationDate": "2021-01-14",
"courseLevel": "Advanced"
}
],
"price": {
"amount": 100.0,
"discount": 30.0,
"paymetType": "VISA CREDIT CARD",
"currency": "SGD"
}
}
]
}
Standalone WireMock Stub Server Creation
Now, we can create a stub server based on our requirements.
Step-1: Add Required Dependencies to pom.xml
Example
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>WireMockTesting</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>2.25.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
</dependency>
</dependencies>
</project>
Step-2: Create Mock JSON Files
test -> resources -> __files package. I also added extra one more package as json but it is not necessary because we are creating a stub server for REST API with JSON.
Step-3: Coding the Stub Server
JsonUtil.java
This class does a very basic JSON read operation. We will use setJSON and getJSON methods in our stub creation methods.
package utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.json.JSONObject;
import org.json.JSONTokener;
public class JsonUtil{
public JSONObject jsonObject;
private File jsonFile;
public JSONObject getJSON() {
return jsonObject;
}
public JsonUtil setJSON(String path) {
jsonFile = new File(System.getProperty("user.dir") + "/src/test/resources/" + path);
jsonObject = readJSONAsJSONObject();
return this;
}
public JSONObject readJSONAsJSONObject() {
InputStream is = null;
try {
is = new FileInputStream(jsonFile);
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
JSONTokener jsonTokener = new JSONTokener(is);
jsonObject = new JSONObject(jsonTokener);
return jsonObject;
}
}
Stubs.java
In this class, we will create our mocks. Based on Wiremock functionalities, we will use different approaches to create these mocks.
import com.github.tomakehurst.wiremock.WireMockServer;
import utils.JsonUtil;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
public class Stubs {
private JsonUtil jsonUtil;
public WireMockServer wireMockServer;
public Stubs setUp() {
wireMockServer = new WireMockServer(3467);
wireMockServer.start();
jsonUtil = new JsonUtil();
return this;
}
public Stubs resetServer() {
wireMockServer.resetAll();
return this;
}
public Stubs stubForCreateCart(String responseFileName) {
wireMockServer.stubFor(post("/carts")
.withHeader("Content-Type", equalToIgnoreCase("application/json"))
.withHeader("Accept", equalToIgnoreCase("application/json"))
.withHeader("Version", equalToIgnoreCase("v1"))
.withHeader("Client", equalToIgnoreCase("Android"))
.withHeader("Authorization", equalToIgnoreCase("Bearer MySecretToken"))
.withRequestBody(matchingJsonPath("$.customer.firstName", equalTo("Neeraj")))
.withRequestBody(matchingJsonPath("$.customer.lastName", equalTo("Bakhtani")))
.willReturn(aResponse()
.withStatus(201)
.withHeader("Content-Type", "application/json")
.withBodyFile("json/" + responseFileName)));
return this;
}
public Stubs stubForGetCartSingle(String responseFileName) {
wireMockServer.stubFor(get("/carts/quil514c-9678-4a4b-b32d-550b7fc3cfb2?productCount=1")
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("json/" + responseFileName)));
return this;
}
public Stubs status() {
System.out.println("Stubs Started!");
return this;
}
}
StubServerMain.java
We will chain our stub creation methods in the main class.
public class StubServerMain {
public static Stubs stubs = new Stubs();
public static void main(String[] args) {
stubs.setUp()
.stubForCreateCart("CreateCartSuccessResponse.json")
.stubForGetCartSingle("CreateCartSuccessResponse.json")
.status();
}
}
Find sample code in Git
https://github.com/neeraj19a/MockingAPIUsingWireMock
Use Potman Collection file: Sample API for Test.postman_collection.json (in above Git Link only)
To run this As Application
click Run--> Edit Configuration
click +
We are often in a need to create stubs or mocks when the API under test is not completely ready or we need to test the external systems without getting affected by any external environmental problems.
Requirements for our API service:
Our service has all the below specifications.
Endpoint URL (Base path and resource path)
Body
Query Parameters
Path Parameters
Headers
Our product type is courses and we can do below operations for shoppingcart service:
Create a shopping cart. (POST)
Get/Retrieve a shopping cart details. (GET)
Now let’s define the service requirements step by step.
Service URL
Base URL http://test.myshop.com
Base Path carts
Headers:
Content-Type application/json
Accept application/json
Version v1
Client Android
Authorization Bearer <token>
Create a Shopping Cart
Method: POST
Resource Path: No resource path required.
Example Request: POST /carts
Body:
Our shopping cart has customer and products attributes and they have their own attributes as shown below.
{
"customer":{
"id":"9879898787",
"firstName":"Neeraj",
"lastName":"Bakhtani",
"email":"myemailId@gmail.com"
},
"products":[
{
"description":"Rest API mocking using WireMock",
"type":"Course",
"productAttributes":[
{
"courseLenght":"5 hours",
"courseRating": "5 stars",
"courseCreationDate":"2021-01-14",
"courseLevel":"Advanced"
}
],
"price":{
"amount": 100.0,
"discount": 30.0,
"paymetType":"VISA CREDIT CARD",
"currency": "SGD"
}
}
]
}
Response:
{
"customer":{
"id":"9879898787",
"firstName":"Neeraj",
"lastName":"Bakhtani",
"email":"myemailId@gmail.com"
},
"products":[
{
"description":"Rest API mocking using WireMock",
"type":"Course",
"productAttributes":[
{
"courseLenght":"5 hours",
"courseRating": "5 stars",
"courseCreationDate":"2021-01-14",
"courseLevel":"Advanced"
}
],
"price":{
"amount": 100.0,
"discount": 30.0,
"paymetType":"VISA CREDIT CARD",
"currency": "SGD"
}
}
]
}
Get a Shopping Cart
Method: GET
Resource Path: {cartId}
Query Param: productCount (I added to distinguish 1 and 2 product mocking. Normally, we do not need this kind of QueryParams.)
Example Request: GET /carts/quil514c-9678-4a4b-b32d-550b7fc3cfb2?productCount=1
Response
{
"id": "quil514c-9678-4a4b-b32d-550b7fc3cfb2",
"customer": {
"id": "9879898787",
"firstName": "Neeraj",
"lastName": "Bakhtani",
"email": "myemailId@gmail.com"
},
"products": [
{
"id": "93b55282-334c-48b0-a8f7-a9d5eef9c4b9",
"description": "Rest API mocking using WireMock",
"type": "Course",
"productAttributes": [
{
"courseLenght": "5 hours",
"courseRating": "5 stars",
"courseCreationDate": "2021-01-14",
"courseLevel": "Advanced"
}
],
"price": {
"amount": 100.0,
"discount": 30.0,
"paymetType": "VISA CREDIT CARD",
"currency": "SGD"
}
}
]
}
Standalone WireMock Stub Server Creation
Now, we can create a stub server based on our requirements.
Step-1: Add Required Dependencies to pom.xml
Example
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>WireMockTesting</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>2.25.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
</dependency>
</dependencies>
</project>
Step-2: Create Mock JSON Files
test -> resources -> __files package. I also added extra one more package as json but it is not necessary because we are creating a stub server for REST API with JSON.
Step-3: Coding the Stub Server
JsonUtil.java
This class does a very basic JSON read operation. We will use setJSON and getJSON methods in our stub creation methods.
package utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.json.JSONObject;
import org.json.JSONTokener;
public class JsonUtil{
public JSONObject jsonObject;
private File jsonFile;
public JSONObject getJSON() {
return jsonObject;
}
public JsonUtil setJSON(String path) {
jsonFile = new File(System.getProperty("user.dir") + "/src/test/resources/" + path);
jsonObject = readJSONAsJSONObject();
return this;
}
public JSONObject readJSONAsJSONObject() {
InputStream is = null;
try {
is = new FileInputStream(jsonFile);
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
JSONTokener jsonTokener = new JSONTokener(is);
jsonObject = new JSONObject(jsonTokener);
return jsonObject;
}
}
Stubs.java
In this class, we will create our mocks. Based on Wiremock functionalities, we will use different approaches to create these mocks.
import com.github.tomakehurst.wiremock.WireMockServer;
import utils.JsonUtil;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
public class Stubs {
private JsonUtil jsonUtil;
public WireMockServer wireMockServer;
public Stubs setUp() {
wireMockServer = new WireMockServer(3467);
wireMockServer.start();
jsonUtil = new JsonUtil();
return this;
}
public Stubs resetServer() {
wireMockServer.resetAll();
return this;
}
public Stubs stubForCreateCart(String responseFileName) {
wireMockServer.stubFor(post("/carts")
.withHeader("Content-Type", equalToIgnoreCase("application/json"))
.withHeader("Accept", equalToIgnoreCase("application/json"))
.withHeader("Version", equalToIgnoreCase("v1"))
.withHeader("Client", equalToIgnoreCase("Android"))
.withHeader("Authorization", equalToIgnoreCase("Bearer MySecretToken"))
.withRequestBody(matchingJsonPath("$.customer.firstName", equalTo("Neeraj")))
.withRequestBody(matchingJsonPath("$.customer.lastName", equalTo("Bakhtani")))
.willReturn(aResponse()
.withStatus(201)
.withHeader("Content-Type", "application/json")
.withBodyFile("json/" + responseFileName)));
return this;
}
public Stubs stubForGetCartSingle(String responseFileName) {
wireMockServer.stubFor(get("/carts/quil514c-9678-4a4b-b32d-550b7fc3cfb2?productCount=1")
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("json/" + responseFileName)));
return this;
}
public Stubs status() {
System.out.println("Stubs Started!");
return this;
}
}
StubServerMain.java
We will chain our stub creation methods in the main class.
public class StubServerMain {
public static Stubs stubs = new Stubs();
public static void main(String[] args) {
stubs.setUp()
.stubForCreateCart("CreateCartSuccessResponse.json")
.stubForGetCartSingle("CreateCartSuccessResponse.json")
.status();
}
}
Find sample code in Git
https://github.com/neeraj19a/MockingAPIUsingWireMock
Use Potman Collection file: Sample API for Test.postman_collection.json (in above Git Link only)
To run this As Application
click Run--> Edit Configuration
click +
No comments:
Post a Comment