Hello, a few months ago, Ali Aktolun briefly explained how to use Karate Framework for web service testing. Here’s the article. You need to be familiar with Karate in order to understand the Calling Custome Java Code in Karate API Tests tutorial.
The most important feature of Karate is “no coding”. But there are cases where you need to take custom actions like saving a response to a file, file reading or writing, etc. In this tutorial, I’ll explain how to use Java codes in Karate API tests and Karate Projects.
My use case is testing web services which require authentication. My first web service does the authentication and creates a token, then all other services use that token. But generated token belongs to “Authentication test” context. When I execute the next web service, this token is not recognized as it belongs to previous test context. So what should I do?
- I can use Karate’s built-in call method. This method will call “Authentication Service” before execution of any other scenarios. So I will have multiple web service calls which will increase execution time.
- I can save generated token in a file. Then I read this token before other scenario’s execution. By this way, I will run the “Authentication Service” once.
Maybe there are other smart solutions to do that but this is the second one is the one I come up with to reduce the execution time for Java Code in Karate API Tests.
Implementing Java Code
Let’s start from Java Code that writes to and reads from a properties file. This code simply writes our token to config.properties file by using write method. Then you can read the value by using read method.
public void write(Map<String, Object> config) throws IOException { String key = (String) config.get("key"); output = new FileOutputStream(FILE_NAME); prop.setProperty("key", key); prop.store(output, null); }
Write method takes a Map<String, Object> object as an input. I can send a key and its corresponding value as parameters by having this object. In case you want to send one String value, you can change your method signature as below. Implementation depends on you.
public String read(String key) throws IOException { input = new FileInputStream(FILE_NAME); prop.load(input); return prop.getProperty(key); }
Read method only read from the config file by using a key value. As I only send one String, method signature is different than the previous one.
Calling JAVA Code in Karate API Tests
Here’s my test code that creates a token from the authentication server.
Scenario: Login to Loadium Given url 'https://account.loadium.com/uaa/oauth/token?grant_type=password&password=PASS&username=USER&scope=openid' And header Accept = 'application/json' And header Authorization = 'Basic dGVzdGluaXVtU3VpdGVUcnVzdGVkQ2xpZW50OnRlc3Rpbml1bVN1aXRlU2VjcmV0S2V5' And request {} Then method POST Then status 200 * def token = $.access_token
I need to call write method in this scenario to store generated token into a file.
Defining File Write Functionality
* def doStorage = """ function(args) { var DataStorage = Java.type('examples.DataStorage'); var dS = new DataStorage(); return dS.write(args); } """
This command creates an object with doStorage name that you will use in your Karate DSL test. Blue ones are the name of my Java file. The green one is the package name of my Java class. As you can see we create a variable dS then call write method. This is the method name that we have in Java class.
Calling File Write Functionality
I add the below line to my scenario.
* def result = call doStorage {'key': #(token)}
call is a built-in component of Karate framework. doStorage is the variable that we created earlier. {‘key’: #(token)} is the input that we provide.
#(token) allows you to get the value of the token variable.
So final version of our test is below.
Scenario: Login to Loadium * def doStorage = """ function(args) { var DataStorage = Java.type('examples.DataStorage'); var dS = new DataStorage(); return dS.write(args); } """ Given url 'https://account.loadium.com/uaa/oauth/token?grant_type=password&password=PASS&username=USER&scope=openid' And header Accept = 'application/json' And header Authorization = 'Basic dGVzdGluaXVtU3VpdGVUcnVzdGVkQ2xpZW50OnRlc3Rpbml1bVN1aXRlU2VjcmV0S2V5' And request {} Then method POST Then status 200 * def token = $.access_token * def result = call doStorage {'key': #(token)}
Defining File Read Functionality into Karate Test
This test scenario fetches some data from the server. We need to provide a token to execute this scenario. Let’s do that.
Scenario: Get All Tests Given url 'https://loadium.io/resource1/api/tests' And header Accept = 'application/json' And header Authorization = 'Bearer ' + result Then method GET Then status 200 * def testKey = $.testBasicDetailsDTOs[0].testKey
Once again we create a doStorage object calling our Java class’ read method.
* def doStorage = """ function(args) { var DataStorage = Java.type('examples.DataStorage'); var dS = new DataStorage(); return dS.read(args); }""
This line creates an object with doStorage name that you will use in your Karate DSL test. Blue ones are the name of my Java file. The green one is the package name of my Java class. As you can see we create a variable dS then call read method. This is the method name that we have in Java class.
Calling File Read Functionality
Then we call our this object with an input. As we stored our token with “key” value, we pass “key” parameter to our method.
* def result = call doStorage 'key'
call is a built-in component of Karate framework. doStorage is the variable that we created earlier. The key is the input that we provide to that function. Then our test scenarios change as below:
Scenario: Get All Tests * def doStorage = """ function(args) { var DataStorage = Java.type('examples.DataStorage'); var dS = new DataStorage(); return dS.read(args); }""" Given url 'https://loadium.io/resource1/api/tests' And header Accept = 'application/json' * def result = call doStorage 'key' And header Authorization = 'Bearer ' + result Then method GET Then status 200 * def testKey = $.testBasicDetailsDTOs[0].testKey
As you can see, there are no limits to what you can achieve with Karate. You can find the project here: https://github.com/swtestacademy/Karate-API-Test-with-Java-Code
Thanks.
Canberk Akduygu

Canberk Akduygu is a Test Lead working in the Netherlands
Very cool! We were also facing this exact problem and considered using file reading/writing, but arrived at a slightly different solution. We used Karate’s built-in ‘callSingle’ function, since it allows you to save returned values across all features. In the config file, we use callSingle to call an initialization Karate feature file that calls the required login endpoint, and then returns the token value to the config file where we save it. That token value can then be used across every subsequent feature file we run, without having to use file reading/writing.
Using Java code in Karate is a great feature too, we are using it for things like custom assertions, and uuid & local date time generation.
Hi Alex,
This sounds great. Can you pls share the code snippets.
Can you share code snipper about this feature? Great solution.
Sir
Can you give example of digest auth with karate api
Mr. Akduygu will reply you back Rahesh. I do not have too much experience in Karate.
can anyone share an example of a simple complete IU project with gatling using the latest karate version 0.9.5, please?
I do not have :(
sorry for the typo, it should read ‘UI’ not IU
Java code to read an excel file, call Java code in Karate API and print them values?