Overview
In this post we will see What is Karate and How to test Rest API with Karate Framework(BDD).
Karate
Karate is a complete DSL and sits on top of Cucumber-JVM. Unlike other automated API testing tools which require a good amount of coding, Karate works out of the box. Test cases are written in Gherkin style text *.feature file.
A Gherkin file is saved with the “.feature” extension. In general feature file starts with a Tag or Feature keyword followed by a description and Scenarios in the format of Given, When and Then along with some assertions.
Maven Setup
If you are using Maven, you need the two following dependencies.
Note: Since Karate 0.3.0 we may choose which HTTP client to use for running our tests. Apache and Jersey implementations are supported. For this post Apache(karate-apache) is used.
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-apache</artifactId>
<version>0.9.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-junit5</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
For Junit 4
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-junit4</artifactId>
<version>0.6.0</version>
<scope>test</scope>
</dependency>
Gradle Setup
testCompile 'com.intuit.karate:karate-junit4:0.6.0'
testCompile 'com.intuit.karate:karate-apache:0.9.6'
Sample UseCase
Let’s assume we have 2 APIs Save and Get users
Save User:
API: POST /karate/users
Request JSON:
{
"userName": "test", // @NotBlank
"password": "test123", // @NotNull
}
Get Users:
API: GET /karate/users?userName=
Request Param (Optional): userName
Response:
[
{
"userName": "test",
"password": "test123",
"createdDateTime": "2021-05-16T18:52:26.435"
}
]
Refer DTO and Controller logic for more in detail.
Get Users Feature file
In Get User test we will write Scenario to
- validate all User response and status code
- validate User response and status code when pathParam is passed
Feature: Test User Get Info by UserName
Background:
* def baseUrl = karate.properties['baseUrl']
* url baseUrl
Scenario: Get All Users
Given path '/karate/users'
When method GET
Then status 200
* print 'Value of Response: ', response[0].userName
And assert response[0].userName == 'test'
Scenario: Get User by userName
Given path '/karate/users'
And request { userName: 'test' }
When method GET
Then status 200
* print 'Value of Response: ', response[0].userName
And assert response[0].userName == 'test'
Save Users Feature file
In Save User test we will write Scenario to
- validate Save User API with Valid Request and response
- Verify Save API response when mandatory parameters and not passed or Request JSON format is not correct. Data Tables Example is used here to pass multiple cases in single scenarios.
Feature: Test Save User Detail
Background:
# global variable for this feature file
* def baseUrl = karate.properties['baseUrl']
* url baseUrl
* def postJson = {userName:'Hello',password:'123'}
# call once before any test execution. Useful for Data setup
# * callonce read('classpath:preCall.feature');
# call after all scenarios are executed in this feature file. Useful for Data clean up
* configure afterFeature = function(){ karate.print('post feature logic goes here'); }
Scenario: Save User Detail
Given path '/karate/users'
And request postJson
When method POST
Then status 200
And match response == {'message' : 'success' }
Scenario Outline: <index> - <useCase>:
validate different scenarios for bad request
Given path '/karate/users'
And request <requestJson>
When method POST
Then status <status>
And match response == <response>
Examples:
| index | useCase | requestJson | status | response |
| 1 | No Request Body | null | 400 | {"timestamp":"#string","status":400,"error":"#string","message":"#string","path":"/karate/users"} |
| 2 | Wrong Request Body | 'test' | 415 | {"timestamp":"#string","status":415,"error":"#string","message":"#string","path":"/karate/users"} |
| 3 | Empty Request Body | {} | 400 | {"password":"must not be null","userName":"must not be blank"} |
| 4 | UserName is Null | {'password': '123'} | 400 | {"userName":"must not be blank"} |
| 5 | UserName is Empty | {"userName": "","password": "123"} | 400 | {"userName":"must not be blank"} |
| 6 | Password is Null | {"userName": "Test"} | 400 | {"password":"must not be null"} |
Keywords
- Feature: One liner Description about feature
- Background: Define global variables used across all scenarios written in this feature file
- karate.properties[‘baseUrl’]: read argument passed from cmd eg: mvn clean test -DbaseUrl=http://localhost:8080
- callonce: will be called once before any scenarios start execution.
- configure afterFeature: will be called post all scenarios are executed.
- Scenario: single test case with single response matching
- Scenario Outline: for multiple cases must have Examples keyword to add multiple test cases
- We also can use markers like #null, #notnull, #boolean, #number, #string, #array, #object. Refer here for more detail
Running Tests
Here Karate with JUnit is used. We have options to run test cases in parallel or sequential. In addition, we also have the option to generate a test Report using 3rd party library
import com.intuit.karate.junit5.Karate;
import com.intuit.karate.Results;
import com.intuit.karate.Runner;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import net.masterthought.cucumber.Configuration;
import net.masterthought.cucumber.ReportBuilder;
import org.apache.commons.io.FileUtils;
public class KarateDemoTest {
// // Run Sequential tests
// @Karate.Test
// Karate testAll() {
// return Karate.run().relativeTo(getClass());
// }
@Test
void testParallel() {
Results results = Runner.builder().relativeTo(getClass()).outputCucumberJson(true).parallel(5);
generateReport(results.getReportDir());
assertEquals(0, results.getFailCount(), results.getErrorMessages());
}
public static void generateReport(String karateOutputPath) {
Collection<File> jsonFiles = FileUtils.listFiles(new File(karateOutputPath), new String[] {"json"}, true);
List<String> jsonPaths = new ArrayList(jsonFiles.size());
jsonFiles.forEach(file -> jsonPaths.add(file.getAbsolutePath()));
Configuration config = new Configuration(new File("target"), "demo");
ReportBuilder reportBuilder = new ReportBuilder(jsonPaths, config);
reportBuilder.generateReports();
}
}
Conclusion
In this post, we took a tour of the Karate Testing Framework(BDD).
For trying out locally download source code from Git and start the application locally. Move to the integration-test folder and execute test cases. Refer to the respective readme for more detail.
You can also refer to generated Reports here for reference.
0 Comments