Code & QA Zone: Tutorials, Tools, Guides & Tips for Developers & Testers

How and When to Use callonce vs call in Karate DSL

One of the most useful features in Karate DSL is the ability to reuse logic by invoking external feature files or utility scripts.

For this, Karate provides two very similar functions: call and callonce.

At first glance they seem almost identical, but their execution behavior is very different:

  • call executes every time it is reached.
  • callonce executes once and reuses the cached result.

I realized how important this distinction was while working on a test suite where a utility feature declared in the Background was unintentionally triggering the same API request before every scenario because I was using call instead of callonce.

In small suites this may go unnoticed, but in larger suites it can lead to unnecessary API traffic, slower execution times, and redundant setup operations.

That’s why understanding when to use each one is essential for building scalable and efficient Karate test suites.

Where These Functions Can Be Used

Both call and callonce can be used:

  • inside a Background,
  • or directly inside a Scenario.

However, their impact becomes more noticeable when used in a Background, because the Background executes before every scenario.

Example

Background:
  * def auth = call read('utils/get-auth-token.feature')

If the feature contains 10 scenarios, the authentication feature above will execute 10 times.

In cases like this, callonce is often the better choice.

1. Using call (For Fresh or Independent Data)

Use call when each scenario needs its own unique or isolated data.

This is useful when:

  • Tests should not share state.
  • Data collisions must be avoided.
  • Setup data should be recreated every time.

Example: Creating Independent Orders

Feature: Independent test data using 'call'

Background:
  # Creates a fresh order for every scenario
  * def order = call read('utils/create-order.feature')

Scenario: Cancel order
  Given path 'orders', order.id, 'cancel'
  When method post
  Then status 200

Scenario: Update shipping address
  Given path 'orders', order.id, 'shipping'
  And request { city: 'Cordoba' }
  When method put
  Then status 200

Here, using call makes sense because each scenario should work with its own independent order.

2. Using callonce (For Shared or Reusable Data)

Use callonce when the returned data can safely be reused across scenarios.

This is commonly used for:

  • Authentication tokens.
  • Configuration data.
  • Master records.
  • Reusable setup data.

Example: Reusing an Authentication Token

Feature: Shared authentication using 'callonce'

Background:
  # Login executes only once for the feature
  * def auth = callonce read('utils/get-auth-token.feature')
  * def token = auth.accessToken

Scenario: Get customer profile
  Given header Authorization = 'Bearer ' + token
  Given path 'customers', 101
  When method get
  Then status 200

Scenario: Get customer orders
  Given header Authorization = 'Bearer ' + token
  Given path 'customers', 101, 'orders'
  When method get
  Then status 200
  • Without callonce, the login request would execute before every scenario.
  • With callonce, Karate executes it once and reuses the same result for the rest of the feature.

When to Use Which?

SituationRecommended
Each scenario needs fresh datacall
Data can be shared across scenarioscallonce
Creating unique test entitiescall
Authentication or shared setupcallonce
Dynamic or disposable datacall
Reusable read-only datacallonce

Final Thoughts

The difference between call and callonce is simple, but understanding when to use each one can make your Karate tests cleaner and more efficient.

As a general rule:

  • Use call when scenarios need fresh or isolated data.
  • Use callonce when the same result can safely be reused.