What is contract testing?
Contract testing is a way to ensure that services (an API provider, a client etc.) can communicate with each other.
The contract is between a consumer (for example, a client who wants to receive some data from an app) and a provider (for example, an API on a server that provides the data the client needs). In a microservice architecture, the terms client and server are not always suitable to encapsulate the connectivity between services. Communication methods are different, and the hierarchy of roles is not as clear. For this reason, we stick to consumer and provider in this article.
What is consumer-driven contract testing?
With contract testing, we want to ensure that a service works between a consumer (same as the client) and an API provider (the provider).
What happens when the provider changes a part of the service? You will need to know if the consumer can still use the service and whether the changes still meet the demands of the consumer’s contract. This is when you need to perform consumer-driven contract testing.
Since these contracts are written and managed exclusively by consumers, providers must first obtain permission from consumers before they can make any changes. If providers need to implement new features, they can see which consumers would be affected by the change(s) by looking at the status of the consumer’s contract tests.
Tools for Contract testing:
- Postman (Best to start with and has great feature )
- Pact ( Specialist in this field,Supports all languages, but limited for free version)
- JsonSchema validator / everit ( With Rest assured )
POSTMAN:
- Read this article where I have described how to do schema validation using POSTMAN via ajv library.
- This is another article which explains beautifully an advanced way of contract testing using postman
PACT:
I was studying about contract testing and I bumped on a brilliant conference by Atlassian where two amazing guys discuss how contract testing is very crucial and beneficial in API testing. ( Pretty funny video too 🙂 )
Karthik explains here beautifully about how to implement pact in API testing.
Everit
https://github.com/everit-org/json-schema
Everit is better than JsonSchema validator as it gives better error debugging info in failure.
<dependency>
<groupId>org.everit.json</groupId>
<artifactId>org.everit.json.schema</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.2.0</version>
</dependency>
Lets take and example of a Rest assured request which will return the below json body .
We will validate this response using json schema.
{
"id": 1,
"username": "Avishek"
}
Now we need to convert this json to json schema. There are many online tools available. We will use below website :
https://jsonschema.net/
Paste the json on the left pane and click submit, it will generate the schema.
Save the schema in a .json file ( Lets name it as UserSchema.json ). it will look something like below:
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "http://example.com/example.json",
"type": "object",
"title": "The root schema",
"description": "The root schema comprises the entire JSON document.",
"default": {},
"examples": [
{
"id": 1,
"username": "Avishek"
}
],
"required": [
"id",
"username"
],
"properties": {
"id": {
"$id": "#/properties/id",
"type": "integer",
"title": "The id schema",
"description": "An explanation about the purpose of this instance.",
"default": 0,
"examples": [
1
]
},
"username": {
"$id": "#/properties/username",
"type": "string",
"title": "The username schema",
"description": "An explanation about the purpose of this instance.",
"default": "",
"examples": [
"Avishek"
]
}
},
"additionalProperties": true
}
Here is the method for validating schema using everit:
public static boolean validateJsonSchema(String jsonSchemaFilePath, String jsonString) {
boolean validationFlag = false;
try {
JSONTokener schemaData = new JSONTokener(new FileInputStream(new File(jsonSchemaFilePath)));
JSONObject jsonSchema = new JSONObject(schemaData);
Schema schema = SchemaLoader.load(jsonSchema);
schema.validate(new JSONObject(jsonString));
validationFlag = true;
} catch (Exception e) {
System.out.println("Schema validation failed: \n" + e);
}
return validationFlag;
}
Now we will make a request with Rest assured and validate the response with above method:
Response resp = given()
.log().all()
.when()
.get("/userInfo")
.then()
.log().all()
.assertThat().statusCode(200)
.extract().response();
Assert.assertTrue(validateJsonSchema("UserSchema.json", resp.asString()));
Jsonschema validator:
If we want to validate using JsonSchema validator:
given()
.log().all()
.when()
.get(ApiPath.getAthlete)
.then()
.log().all()
.assertThat().statusCode(200)
.body(matchesJsonSchemaInClasspath("UserSchema.json"));
Credits:
https://saucelabs.com/blog/intro-to-contract-testing-getting-started-with-postman
https://medium.com/@liran.tal/a-comprehensive-guide-to-contract-testing-apis-in-a-service-oriented-architecture-5695ccf9ac5a
https://saucelabs.com/blog/intro-to-contract-testing-getting-started-with-postmanhttps://medium.com/@liran.tal/a-comprehensive-guide-to-contract-testing-apis-in-a-service-oriented-architecture-5695ccf9ac5a
https://medium.com/@liran.tal/a-comprehensive-guide-to-contract-testing-apis-in-a-service-oriented-architecture-5695ccf9ac5a