< Back

Integrating Gatling into a Cucumber Framework: Challenges, Solutions, and Lessons Learned

Author

Jeroen Verschaeren

Date

21/06/2026

Share this article

Introduction

Our current test automation framework uses Cucumber, Rest Assured, and Spring Boot. Because of how our CI/CD pipeline was set up, we could only manage one testing project. When we needed to add performance and load testing with Gatling, the challenge became clear: integrate Gatling into the existing framework without starting a new project.

What seemed simple at first soon uncovered several technical hurdles that needed careful planning and step-by-step problem-solving.

The First Challenge: Spring Bean Integration

The first issue came up right away. Gatling simulations could not resolve Spring beans like the existing Cucumber framework.

This limitation meant I could not directly reuse:

  • Existing API endpoint configurations

  • Request and response models

  • Shared framework components

Without access to these components, I would face a lot of code duplication, which I wanted to avoid.

Finding a Different Approach

While looking for solutions, I recalled that Cucumber supports multiple runners with various configurations.

This inspired a new idea.

Instead of trying to fit Gatling into the current setup, I created:

  • A dedicated package for Gatling simulations

  • A separate StressRunner

  • A parent CucumberRunner to manage execution

The goal was to allow functional tests and performance tests to work together in the same project while keeping them logically separated.

The Concurrency Problem

After setting up the runners, another challenge arose.

Our tests depended on shared test data. Since both the functional tests and Gatling simulations accessed the same data sources, concurrency problems began to emerge.

Running both suites at once led to data conflicts and inconsistent test behavior.

To solve this, I took a step back and reevaluated the execution flow.

The Breakthrough: Sequential Execution

The solution was surprisingly straightforward.

I implemented a hook that tracked the completion of the main Cucumber execution. Once all functional tests finished, the hook automatically triggered the Gatling stress tests.

This approach provided several benefits:

  • Functional and performance tests no longer competed for the same data.

  • Existing test data could still be reused.

  • The framework stayed as a single project, meeting CI/CD requirements.

  • Gatling simulations could run reliably alongside Cucumber features.

This was the first major milestone where the integration started to work as intended.

Making Gatling Useful for Developers

Although the technical integration was done, another need came up.

The development team wanted to use load tests not only for performance checks but also for debugging.

At first, the Gatling simulations were hardcoded:

  • Fixed scenarios

  • Fixed durations

  • No runtime customization

This made them less flexible and hard to use for investigating specific issues.

To address this, I added dedicated Gatling step definitions within Cucumber.

These steps allowed users to define:

  • Number of concurrent users

  • Target endpoints

  • Test duration

  • Additional simulation parameters

As a result, performance tests became configurable directly from feature files, making them much more helpful for developers needing to reproduce and debug issues under load.

The Final Result

By carefully implementing each layer step by step, the framework evolved into a solution where:

  • Functional testing and load testing coexist in a single project.

  • Gatling simulations can run after Cucumber scenarios.

  • Test data conflicts are avoided.

  • Developers can configure load tests through Cucumber features.

  • Existing framework components can still be used where appropriate.

Most importantly, developers gained an easy way to reproduce performance-related issues and validate fixes more effectively.

Key Takeaway

The biggest lesson from this project was not technical—it was methodological.

When faced with a complex integration challenge, avoid jumping in with the complete end goal in mind. Instead:

  • Start with the smallest possible working solution.

  • Validate that it works.

  • Expand gradually.

  • Tackle problems one layer at a time.

By focusing on small, achievable steps rather than the whole problem at once, what initially seemed like a tough integration became a successful and manageable solution.

Start small, make it work, and then build on it.