Karate Framework:
In this article, we’ll get to know API Testing with Karate Framework and go over the sample project.
With the popularity of BDD (Behaviour Driven Development), using the gherkin style in the automation project makes sense because offering development that everyone can understand has many benefits and provides a quick process for the team. Let’s explain the benefits of this by comparing Karate with Rest Assured Framework.
Comparison of Karate with Rest-Assured Framework
Firstly I started to experience Rest-Assured Framework for it but after exploring the Karate Framework it happened to be my favorite one. Because building a structure is very important to create a project that is suitable for growth. Most of the time it’s a cost for the team to understand and build the project. Unlike Rest-Assured, The utilization of Karate has proven to be cost-effective. Karate already creates ready-to-use gherkin steps for almost every action with API. We can think of it as a collaborative project for each different API project.
I won’t go into much detail about Rest-Assured but if you want to compare them, I’ll be adding projects for the same API created with Karate and Rest-Assured.
After comparing these frameworks in general, Let’s look at how we can use the Karate framework.
Set up Environment
Karate Framework supports JDK 1.8 and higher, so I use JDK 11.
You can find below the pom.xml example. I used ‘maven-archetype-quickstart’ when I started my project. You can select this archetype from IDE.
The file has 3 dependencies, one of them is JUnit which I added to manage parallel execution for test cases, and others are used for Karate.
<?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>Grocery-Karate-API-Automation</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>Grocery-Karate-API-Automation</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>11</java.version> <maven.compiler.version>3.8.1</maven.compiler.version> <maven.surefire.version>2.22.2</maven.surefire.version> <karate.version>1.2.0</karate.version> </properties> <dependencies> <dependency> <groupId>com.intuit.karate</groupId> <artifactId>karate-junit5</artifactId> <version>${karate.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>com.intuit.karate</groupId> <artifactId>karate-apache</artifactId> <version>0.9.6</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <testResources> <testResource> <directory>src/test/java</directory> </testResource> </testResources> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle --> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>${maven.compiler.version}</version> <configuration> <encoding>UTF-8</encoding> <source>${java.version}</source> <target>${java.version}</target> <compilerArgument>-Werror</compilerArgument> </configuration> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>${maven.surefire.version}</version> <configuration> <argLine>-Dfile.encoding=UTF-8</argLine> <includes> <include>**/*TestRunner*.java</include> </includes> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>
As a second action, to manage environment configuration and the other ones such as base URL, API key, etc., we should create a karate-config.js file into the src/test/java path. Be sure this file is in the correct path otherwise, you can not use the configuration that into the karate-config.js
function fn() { var env = karate.env; // get system property 'karate.env' karate.log('karate.env system property was:', env); if (!env) { env = 'dev'; } var config = { env: env, baseUrl: 'https://petstore.swagger.io' } if (env == 'dev') { // customize // e.g. config.foo = 'bar'; } else if (env == 'e2e') { // customize } return config; }
Now we’ve completed everything we need to start writing a script!
Let’s look at the examples with GET/POST/UPDATE/DELETE requests with Karate. After creating a sample feature file into the src/test/java path, you can write example requests like below.
There are the most basic GET and POST request examples. If you write a baseUrl, it reads from the karate config file automatically.
And also, you can verify the response with several types of match methods. (exact match, contains, present, etc.)
Feature: Grocery API Background: The Request Body Configuration # Set a configuration for the payload * url baseUrl Scenario: Get All Products from Grocery Given header Content-Type = 'application/json' And path '/allGrocery' When method get Then status 200 And match response.data[*].id == '#present' And match response.data[*].price == '#present' And match response.data[*].name == '#present' And match response.data[*].stock == '#present' Scenario Outline: Get Grocery Details with a name Given header Content-Type = 'application/json' And path '/allGrocery/<name>' When method get Then status 200 And match response.data[0].name == "<name>" And match response.data[0].id == '#present' And match response.data[0].price == '#present' And match response.data[0].stock == '#present' Examples: | name | | apple | | grapes | Scenario: Add a new product to the Grocery Basket * def jsonBody = """ { "id": 4, "name": "string", "price": 12.3, "stock": 3 } """ Given header Content-Type = 'application/json' And path '/add' And request jsonBody When method post Then status 201 And response.message == "success"
As you can see above, you can define the body payload in the scenario on the feature file and also you can create a JSON file and read it in the feature file.
On the other hand, Karate supports getting value from created java classes into the feature file. Compared with Rest Assured Framework, this feature makes the best difference in readability. You can find an example related to this.
{ "id": 0, "category": { "id": 0, "name": "string" }, "name": "hola", "photoUrls": [ "string" ], "tags": [ { "id": 0, "name": "string" } ], "status": "available" }
Lastly, I’m adding the example of the delete and update requests.
Feature: Petstore Background: The Request Body Configuration # Set a configuration for the payload * url baseUrl * def requestPayload = read('classpath:payload/pet.json') * set requestPayload.id = Java.type('utils.TestDataCreator').getID() * set requestPayload.category.id = Java.type('utils.TestDataCreator').getID() * set requestPayload.category.name = Java.type('utils.TestDataCreator').getDogCategoryName() * set requestPayload.name = Java.type('utils.TestDataCreator').getDogName() * set requestPayload.photoUrls[0] = Java.type('utils.TestDataCreator').getFileName() * set requestPayload.tags[0].name = requestPayload.name * set requestPayload.status = Java.type('utils.TestDataCreator').getStatus()[0] Scenario: Delete a pet # Create a new pet as the precondition Given header Content-Type = 'application/json' And path '/v2/pet' And request requestPayload When method post Then status 200 # Delete the pet from the store Given header Content-Type = 'application/json' And path '/v2/pet/' + requestPayload.id When method delete Then status 200 And match $.code == 200 Scenario: Updates the pet in the store # Create a new pet as the precondition Given header Content-Type = 'application/json' And path '/v2/pet' And request requestPayload When method post Then status 200 # Create a new pet name & status for updating them. * def newName = Java.type('utils.TestDataCreator').getCatName() * def newStatus = Java.type('utils.TestDataCreator').getStatus()[2] # Send the update request Given header Content-Type = 'application/x-www-form-urlencoded' And path '/v2/pet/' + requestPayload.id And form field name = newName And form field status = newStatus When method post Then status 200 * print response
Configuration Parallel Testing
Configuration parallel testing is quite easy. We only need the feature file path and JUnit that we added already into the pom.xml.
You can configure how many test cases should be executed simultaneously.
The parallel() method manages how many cases are running at the same time. I preferred 4 cases for my project but we can increase the amount. It doesn’t have any limit.
package runner; import com.intuit.karate.Results; import com.intuit.karate.junit5.Karate; import static org.junit.Assert.*; import org.junit.Test; public class TestRunner { @Test public void testParallel() { Results results = Karate.run("src/test/java/features").parallel(4); assertTrue(results.getErrorMessages(), results.getFailCount() == 0); } }
Summary Report
Karate Framework generates the summary report automatically after running the test case. When all case execution is completed, the HTML report URL is created as follows.
Other Features and References
Karate Framework not only supports JSON as a format but also works on SOAP requests as XML. To give a wide assertion method structure, provide readable and ready-to-use request & response methods, and also retry configurations, this framework meets all the developer’s expectations.
I’m really glad to share my own experience with Karate. If you want also to use Karate for API testing, you can benefit from the main documentation from KarateLabs and also my example projects. Please feel free to ask me anything about it.
- https://github.com/karatelabs/karate
- https://github.com/burcuakkayaa/Grocery-Karate-API-Automation
- https://github.com/burcuakkayaa/Petstore-with-Karate
- https://github.com/burcuakkayaa/rest-assured-petstore
Finally, I’m pleased to be a part of the Insider and very excited about the work we will do in the future. If you would like to learn how we manage QA Process at Insider, you can read this article.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.