Karate API testing framework

puneet vashisth
10 min readJul 27, 2023

What is Karate?

Karate is an Open source tool for API testing (SOAP and Rest) introduced in 2017. It is written in JAVA. We can do API mocking, UI Testing, Performance testing of the APIs as well. It uses BDD syntax to write feature and scenarios.

Features:

Very easy for non-programmers. . .yes this is correct. Although it is written in JAVA but implementation is done using Gherkin syntax in BDD style. So it requires no technical programming language.

Below are some more features available while using Karate-

  1. Parallel testing, Distributed testing
  2. Data driven testing
  3. Debugging and reporting
  4. Cross browser web UI testing
  5. Cross platform Desktop testing
  6. Multi environment testing

Prerequisites:

Java (Do not worry, you don’t need to learn java, you just need to have JAVA in your system). You can check if java is already installed by command java -version.

IDE (Eclipse IDE, IntelliJ, VS code). You can use any of these Platform to write test scripts. In this article/demo we are using Eclipse IDE. You can directly search and download from google.

Dependency management (Maven, Gradle). Now a days you do not need to download separately maven as eclipse comes along with Maven support.

Project setup:

Here we will see how to setup project from scratch. These are very simple steps and lets get started-

Step 1- Open eclipse(This will ask you where to keep project folder. You can go with the suggested one OR can change the folder path).

Step 2- You will find ‘Package explorer’ there you will create first project. There are 2 ways you can create project- Either by clicking on File >> New >> Maven project OR by right click inside Package explorer and New >> Maven project. Now click next >> Click Create a simple project.

Group id and artifact id you can enter like below and click on Finish- (this is just for demo)

Step 3- Now you have to add below Karate dependencies in pom.xml-

Karate Core, Karate Apache, Karate JUnit4

You can simply go to mvnrepository.com and search above dependencies. Add these dependencies in your pom.xml and this will look like-

<dependencies>
<!-- https://mvnrepository.com/artifact/com.intuit.karate/karate-core -->
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-core</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.intuit.karate/karate-apache -->
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-apache</artifactId>
<version>0.9.6</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/com.intuit.karate/karate-junit4 -->
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-junit4</artifactId>
<version>1.3.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>5.7.0</version>
</dependency>

</dependencies>

As soon as you save pom.xml, it will create ‘maven Dependencies’ folder inside your project and all the dependencies will be visible here. So far we have completed setup required for first API test.

Let’s create first API test:

Step 1- Create a feature file under src/test/java folder. OR you can create one folder naming ‘’tests’ under src/test/java and there you can keep all your feature files.

Step 2- Create one feature file e.g. ‘FirstTest.feature’ inside ‘Tests’ folder. If you do not get feature file prefilled with Gherkin syntax, then you need to add Cucumber extension from eclipse marketplace and restart eclipse. It will take few minutes to download and install.

After restarting the eclipse you create new feature file and this time you will get prefilled gherkin syntax like -

Step 3- Now you can remove this sample data and write new Scenario. Feature file starts with “Feature: “ followed by the “Scenario”. (This is the Gherkin syntax, so if you are not aware of Gherkins then you can first go through this link https://cucumber.io/docs/gherkin/). Let us get some sample APIs to automate. You can refer google and pick any sample API. For this article we are using reqres.in where you can find many sample APIs. So your first feature file will look like-

Feature: Sample API tests

Scenario: Test a sample Get API
Given url 'https://reqres.in/api/users?page=2'
When method GET
Then status 200

Syntax here is very simple. Step definitions for url, method or status are predefined. So you just need to pass the endPoints, API type and status code with their respective keywords.

Now you can directly run this feature file by right click and run as cucumber feature. You will get html report after refreshing the project folder inside target >> karate-reports >> karate-summary.html-

If it fails to run for any reason, then you can run it through TestRunner.java file. For that you need to create one file named TestRunner.java inside the same folder.

package tests;
import org.junit.runner.RunWith;
import com.intuit.karate.junit4.Karate;

@RunWith(Karate.class)
public class TestRunner{

}

Right click on this file and run as Junit test and this will run all the feature files present in this folder.

So this way you are successfully able to run your first test case. Let’s discuss more advance test cases like Assertion, response match and all in detail.

Let’s validate response:

So far we have learnt how to request an API using karate and validate the status code. Now we need to validate the API response also and use assertion on the response body. Lets start and follow simple steps.

Use above code and print the response as below-

Feature: Sample API tests

Scenario: Test a sample Get API
Given url 'https://reqres.in/api/users?page=2'
When method GET
Then status 200
And print response
And print responseStatus
And print responseTime

karate provides keyword ‘print’ which is very easy to use and get the response. Now when you will run the feature file again, you will see the response in the karate-summary.html file as-

Now we need to validate the response by using match or Assert like-

Scenario: Get demo and use assertion

Given path '/users'
And param page = 2
When method GET
Then status 200
And print response
And match response.data[0].first_name != null
And assert response.data.length == 6
And match response.data[0].first_name == 'Michael'

Here we are validating if first_name is not blank, length of data is 6 and value of first_name is ‘Micheal’. So, this is the simple way to use validations.

Use Background and param:

In case you have some common parameter to all scenarios , then you can use background which will run before executing every scenario. For ex, there may be any data file to read before every scenario etc. Here we are going to use background to keep common part of the url as-

Feature: Get API demo

Background:

* url 'https://reqres.in/api'
* header Accept = 'application/json'

Scenario: Get demo using background

Given path '/users?page=2'
When method GET
Then status 200
And print response

You need to use ‘path’ in the scenario and pass rest of the endpoint there. Now you can use ‘param’ keyword also and divide the path url too like-

Scenario: Get demo using param

Given path '/users'
And param page = 2
When method GET
Then status 200
And print response

Run it again and see if the request is working as expected-

Let’s explore POST API:

Now we are going to automate POST api using karate. So, before that lets first know why we use POST api? In http, we use POST method to create a new resource e.g. a new user, a new employee or any new data. We require request data or body to hit POST api. Now lets create new feature file to create test scenario say post.feature file. Again we can have POST sample api from https://reqres.in/ . Here we are using POST api “https://reqres.in/api/users” as-

Feature: Post API demo
# Simple post request
Scenario: Post api demo
Given url 'https://reqres.in/api/users'
And request { "name": "Punit","job": "QA"}
When method POST
Then status 201
And print response

We are passing method as ‘POST’ and using ‘request’ keyword to pass the request body. This is the simple way to hit POST api and get response. We can use background in the same manner as already discussed

Feature: Post API demo

Background:
* url 'https://reqres.in/api'
* header Accept = 'application/json'
# POST request with background
Scenario: Post api demo
Given path '/users'
And request { "name": "Punit","job": "QA"}
When method POST
Then status 201
And print response

Now run the feature file and you are going to see request response in the karate-summary.html file as-

So here you can see the request body and same response is getting generated. Now you can apply assertion to validate this as-

Feature: Post API demo

Background:
* url 'https://reqres.in/api'
* header Accept = 'application/json'
Scenario: Post api demo 3
Given path '/users'
And request { "name": "Punit","job": "QA"}
When method POST
Then status 201
And print response
And match response == {"name": "Punit", "job": "QA","id": "#string","createdAt": "#ignore"}

Here we are passing “#ignore” with key “createdAt” because this is a timestamp value and will not remain same with each run, so we are using ignore and not to validate this field. Key “id” will also change every time but its type should remain as string. So we are choosing to validate with “#string”. Lets run and see the result-

Now lets try this expected data to keep in separate json file. You need to create one json file in same tests folder as of now and put expected data here as-

{
"name": "Punit",
"job": "QA",
"id": "#string",
"createdAt": "#ignore"
}

and we can use read json file in the background so that we don’t need to call every time as-

Feature: Post API demo

Background:
* url 'https://reqres.in/api'
* header Accept = 'application/json'
* def expectedOutput = read("response1.json")
Scenario: Post api demo
Given path '/users'
And request { "name": "Punit","job": "QA"}
When method POST
Then status 201
And print response
And match response == expectedOutput

In the same way we can pass request body also in the separate json file say request1.json as-

We can pass the read file in the background also OR in the scenario as well-

Feature: Post API demo

Background:
* url 'https://reqres.in/api'
* header Accept = 'application/json'
* def expectedOutput = read("response1.json")
Scenario: Post api demo
Given path '/users'
And def requestBody = read("request1.json")
And request requestBody
When method POST
Then status 201
And print response
And match response == expectedOutput

So far we have discussed when request and response json files are present in the same ‘tests’ folder. What if these files are present in some different folders? Let’s first create request2.json. file in say ‘data’ folder inside src/test/java. Now we can use karate.properties to get default path and append the file path like here-

Feature: Post API demo

Background:
* url 'https://reqres.in/api'
* header Accept = 'application/json'
* def expectedOutput = read("response1.json")
Scenario: Post api demo
Given path '/users'
And def projectPath = karate.properties['user.dir']
And print projectPath
And def filePath = projectPath+'/src/test/java/data/request2.json'
And print filePath
And def requestBody1 = filePath
And request requestBody1
When method POST
Then status 201
And print response

karate-config.js file:

Karate uses a configuration file named karate-config.js. This can be used to create or store global variables. We can also configure baseurl, connection timeouts, execution environment etc. Karate uses this file before running any scenario. Let’s explore more with following steps-

Step 1- Create a new file in src/test/java and name it as karate-config.js

Step 2- Create a javascript function and add configuration inside that.

function fn(){

}

karate-config.js contains a javascript function that returns a JSON object. The key-values defined in the JSON object are available to all feature files. So let’s create one object variable and pass global variable as-

function fn(){
var config={

name : "Punit",
baseURL : 'https://reqres.in/api'
};
return config;
}

Now create a new feature file say configDemo.feature

Feature: Get config js demo

Background:

* url baseURL
* header Accept = 'application/json'


Scenario: Get config demo 1

Given path '/users?page=2'
When method GET
Then status 200
And print response

So here baseurl will be coming from the config file. Now we can pass timeouts, environment also from config file as-

function fn(){
var config={

name : "Punit",
baseURL : 'https://reqres.in/api'
};

var env = karate.env
karate.log('value of env is :', env);
if(env == 'qa'){
config.baseURL = 'https://reqres.in/api/qa'
}
else if(env == 'dev'){
config.baseURL = 'https://reqres.in/api/dev'
}
else {
config.baseURL = 'https://reqres.in/api'
}

karate.configure('connectTimeout', 5000);
karate.configure('readTimeout', 5000);

return config;
}

To set the environment , we need to pass the value in TestRunner.java file as:

package tests;

import org.junit.BeforeClass;
import org.junit.runner.RunWith;

import com.intuit.karate.junit4.Karate;

@RunWith(Karate.class)

public class TestRunner {

@BeforeClass
public static void before() {

System.setProperty("karate.env", "default");
}

}

So this way we can pass the environment in System.setProperty, whether to run in qa, dev or any default environment.

NOTE: You may need to install json reader javascript file reader from eclipse marketplace.

So this is how you can play with the APIs and use their responses to validation. Karate provides very simple architecture and all the step-definitions are predefined. You simply need to use these keywords as per your requirements. Hope you enjoyed this article and please share any feedback which requires improvement in the article. I would be very happy to hear the improvements.

--

--

puneet vashisth

Sound experience in automation tool | Cypress JS based automation tool | Karate API automation | Selenium | Javascript | Typescript | Cucumber | BDD approach |