Debugging Cucumber Tests

Why Debugging is Important

Debugging Cucumber tests is essential for several reasons:

Common issues that require debugging include undefined steps, element not found errors in Selenium, incorrect API responses, or timing issues in dynamic applications.

Common Debugging Techniques

Below are the most effective techniques for debugging Cucumber tests, with examples to illustrate their use. These methods are applicable to various test types (web, API, mobile) and are designed to be accessible to beginners.

1. Using Dry-Run to Check for Undefined Steps

The dry-run option in Cucumber allows you to verify if all steps in your feature files have corresponding step definitions without executing the tests. This is useful for catching undefined or missing steps early in development.

How to Use Dry-Run

Example Feature File (login.feature):

Feature: User Login
  As a user, I want to log in to the application so that I can access my account.

  Scenario: Successful login
    Given the user is on the login page
    When the user enters "user1" and "pass123"
    Then the user should be redirected to the dashboard

TestRunner (src/test/java/runner/TestRunner.java):

package runner;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@CucumberOptions(
    features = "src/test/resources/features",
    glue = "steps",
    dryRun = true,
    plugin = {"pretty"},
    monochrome = true
)
public class TestRunner {
}

Run Command:

mvn test

Output (if all steps are defined):

Feature: User Login
  Scenario: Successful login
    Given the user is on the login page
    When the user enters "user1" and "pass123"
    Then the user should be redirected to the dashboard

1 Scenarios (1 undefined)
3 Steps (3 undefined)
0m0.000s

If steps are undefined, Cucumber will provide snippets for missing step definitions, which you can copy into your step definition file.

Why Use It?

2. Enabling Monochrome Output

The monochrome option makes console output cleaner by removing color codes, which is especially helpful when reviewing logs in CI/CD systems or terminals.

How to Enable

Example TestRunner:

@CucumberOptions(
    features = "src/test/resources/features",
    glue = "steps",
    plugin = {"pretty", "html:reports/cucumber.html"},
    monochrome = true
)

Run Command:

mvn test

Output (clean, readable format):

Feature: User Login
  Scenario: Successful login
    Given the user is on the login page
    When the user enters "user1" and "pass123"
    Then the user should be redirected to the dashboard

Why Use It?

3. Adding Print Statements or Logging

Adding print statements or using a logging framework (e.g., Log4j, SLF4J) in step definitions helps track execution flow and inspect variable values.

Example Step Definitions (src/test/java/steps/LoginSteps.java):

package steps;

import io.cucumber.java.en.*;

public class LoginSteps {
    @Given("the user is on the login page")
    public void userIsOnLoginPage() {
        System.out.println("Navigating to login page");
    }

    @When("the user enters {string} and {string}")
    public void userEntersCredentials(String username, String password) {
        System.out.println("Username: " + username + ", Password: " + password);
        // Simulate failure
        if (password.equals("wrongpass")) {
            throw new RuntimeException("Invalid credentials");
        }
    }

    @Then("the user should be redirected to the dashboard")
    public void userRedirectedToDashboard() {
        System.out.println("Verifying dashboard redirection");
    }
}

Output (for a failing scenario):

Navigating to login page
Username: user1, Password: wrongpass
java.lang.RuntimeException: Invalid credentials

Using Log4j (optional):
Add Log4j dependency to pom.xml:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.23.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.23.1</version>
</dependency>

Create log4j2.properties in src/test/resources:

appenders = console
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %m%n
rootLogger.level = info
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = STDOUT

Update LoginSteps.java:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class LoginSteps {
    private static final Logger logger = LogManager.getLogger(LoginSteps.class);

    @When("the user enters {string} and {string}")
    public void userEntersCredentials(String username, String password) {
        logger.info("Username: {}, Password: {}", username, password);
        if (password.equals("wrongpass")) {
            throw new RuntimeException("Invalid credentials");
        }
    }
}

Why Use It?

4. Using IDE Debugging Tools

Modern IDEs like IntelliJ IDEA and Eclipse allow you to set breakpoints in step definitions to pause execution and inspect variables, call stacks, and application state.

Steps in IntelliJ IDEA

  1. Open LoginSteps.java.
  2. Click the left margin next to a line (e.g., inside userEntersCredentials) to set a breakpoint.
  3. Right-click TestRunner.java and select Debug.
  4. When execution pauses, inspect variables and step through code using the debugger.

Debug Configuration:

Example:
Set a breakpoint at:

logger.info("Username: {}, Password: {}", username, password);

Run in debug mode to inspect username and password values.

Why Use It?

5. Interpreting Cucumber Reports

Cucumber generates detailed reports (HTML, JSON, JUnit) that highlight failed steps and provide error messages.

Example Feature File with Failure:

Feature: User Login
  @regression
  Scenario: Failed login
    Given the user is on the login page
    When the user enters "user1" and "wrongpass"
    Then the user should be redirected to the dashboard

Run Tests:

mvn test

HTML Report (reports/cucumber.html):

JSON Report (reports/cucumber.json):

[
  {
    "elements": [
      {
        "name": "Failed login",
        "steps": [
          {"name": "the user enters \"user1\" and \"wrongpass\"", "result": {"status": "failed", "error_message": "java.lang.RuntimeException: Invalid credentials"}}
        ]
      }
    ]
  }
]

Why Use It?

6. Debugging Common Scenarios

Different test types require specific debugging approaches. Below are tips for common scenarios:

Web Tests (Selenium)

API Tests (REST-assured)

Mobile Tests (Appium)

Why Use It?

7. Using Scenario Hooks for Debugging

Scenario hooks (@Before, @After) can add debugging capabilities, such as capturing screenshots on failure.

Example: Screenshot on Failure:

import io.cucumber.java.After;
import io.cucumber.java.Scenario;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;

@After
public void tearDown(Scenario scenario) {
    if (scenario.isFailed() && driver != null) {
        byte[] screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
        scenario.attach(screenshot, "image/png", "failure-screenshot");
    }
    if (driver != null) {
        driver.quit();
    }
}

Why Use It?

8. Using the @debug Tag

You can use a custom @debug tag to enable debugging for specific scenarios, such as adding extra logging or pausing execution.

Example:

@debug
Scenario: Debug login
  Given the user is on the login page
  When the user enters "user1" and "pass123"
  Then the user should be redirected to the dashboard

Step Definition:

@When("the user enters {string} and {string}")
public void userEntersCredentials(String username, String password) {
    logger.info("Debug mode: Entering username: {}, Password: {}", username, password);
    // Add breakpoint or extra logging
}

Run with @debug:

mvn test -Dcucumber.filter.tags="@debug"

Why Use It?

Best Practices for Debugging

  1. Start with Dry-Run: Always check for undefined steps before running tests.
  2. Use Clear Logging: Add meaningful log messages to track execution.
  3. Leverage IDEs: Use breakpoints for complex issues.
  4. Review Reports: Analyze HTML reports for failure details.
  5. Collaborate: Share logs and screenshots with the team to clarify issues.
  6. Test Incrementally: Debug one scenario at a time to isolate problems.

Troubleshooting Debugging Issues

Tips for Beginners

🤖
PrepCampusPlus AI Tutor
Scroll to Top