---
title: Selenium with Java, TestNG and Cucumber | TestingBot
description: Automated Selenium testing with TestNG and Cucumber. Use BDD testing
  with Cucumber and Java to run tests on remote browsers on TestingBot.
source_url:
  html: https://testingbot.com/support/web-automate/selenium/java/testng-cucumber
  md: https://testingbot.com/support/web-automate/selenium/java/testng-cucumber/index.md
---
# TestNG & Cucumber Automated Testing

Please consult the [TestNG + Cucumber example repository](https://github.com/testingbot/java-testng-cucumber-example) to see a simple example on how to run TestNG & Cucumber tests on TestingBot.

TestNG is a powerful testing framework inspired by JUnit and NUnit but with more flexible and robust features. It is widely used by Java enthusiasts for testing because it offers powerful annotations, test configuration and parallel testing.

Cucumber is a popular tool for Behavior-Driven Development (BDD), allowing test scripts to be written in a human-readable format using the Gherkin language. Because Cucumber uses this natural-like language, it enables collaboration between technical and non-technical team members.

To get started, let's go through all the necessary steps required to run your first test with TestNG and Cucumber on TestingBot.

## Prerequisites

Let's start with making sure Java is available on your system.

**For Windows:**
- You can download Java for Windows from [Java.com](https://www.java.com/en/download/manual.jsp)
- Run the installer and follow the setup wizard to install Java. 

**For Linux (Debian/Ubuntu):**

    sudo apt-get install openjdk-17-jdk

**For macOS:**

    brew install openjdk@17

Alternatively, download from [Eclipse Adoptium](https://adoptium.net/).

## Set up pom.xml dependencies

Now we can specify which dependencies we need to be able to run a test. Create a new file called `pom.xml` and make sure to define at least the following dependencies:

- `io.cucumber:cucumber-java``io.cucumber:cucumber-testng``org.testng:testng``org.seleniumhq.selenium:selenium-java`

    <?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>
        <artifactId>testingbot-testng-cucumber</artifactId>
        <groupId>com.testingbot</groupId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
        <name>testingbot_cucumber_testng</name>
        <description>An example project to run Cucumber + TestNG tests on TestingBot's browser grid</description>
        <dependencies>
            <dependency>
                <groupId>io.cucumber</groupId>
                <artifactId>cucumber-java</artifactId>
                <version>7.22.1</version>
            </dependency>
            <dependency>
                <groupId>io.cucumber</groupId>
                <artifactId>cucumber-testng</artifactId>
                <version>7.22.1</version>
            </dependency>
            <dependency>
                <groupId>org.testng</groupId>
                <artifactId>testng</artifactId>
                <version>7.11.0</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.seleniumhq.selenium</groupId>
                <artifactId>selenium-java</artifactId>
                <version>4.33.0</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.13.0</version>
                    <configuration>
                        <source>17</source>
                        <target>17</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>3.2.5</version>
                    <configuration>
                    	<parallel>classes</parallel>
              			<threadCount>40</threadCount>
                        <redirectTestOutputToFile>false</redirectTestOutputToFile>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>

## Project Structure

Now we need to create a folder structure that will contain the `.feature` files and step definitions.

Create a folder for the `.feature` files:

    mkdir -p src/test/resources/features

We can also define directories for the step definitions, driver and the TestingBot runner class:

    mkdir -p src/test/java/com/testingbotdemo/selenium/cucumber/{definitions,drivers,runners}

## Define TestingBot driver

Now we can define a custom driver that will run the tests on the TestingBot grid:

    package com.testingbotdemo.selenium.cucumber.drivers;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    import org.openqa.selenium.remote.RemoteWebDriver;
    import java.net.URL;
    import java.net.MalformedURLException;
    import java.util.HashMap;
    import java.util.Map;
    
    public class TestingBotDriver {
    
        public static WebDriver getDriver() {
            String key = System.getenv("TESTINGBOT_KEY");
            String secret = System.getenv("TESTINGBOT_SECRET");
            String hubURL = "https://" + key + ":" + secret + "@hub.testingbot.com/wd/hub";
    
            ChromeOptions options = new ChromeOptions();
            options.setPlatformName("WIN11");
            options.setBrowserVersion("latest");
    
            Map<String, Object> tbOptions = new HashMap<>();
            tbOptions.put("name", "Cucumber Example");
            tbOptions.put("build", "build-1");
            options.setCapability("tb:options", tbOptions);
    
            try {
                return new RemoteWebDriver(new URL(hubURL), options);
            } catch (MalformedURLException e) {
                e.printStackTrace();
                throw new RuntimeException("Invalid URL provided for TestingBot hub", e);
            }
        }
    }

We will need to make sure to later specify the `TESTINGBOT_KEY` and `TESTINGBOT_SECRET` environment variables to authenticate and run tests on the TestingBot remote browser grid.

The `ChromeOptions` class is used to define which remote browser we would like to run this Cucumber test on.

## Test Runner

Next, let's create a Test runner class that will use the `CucumberOptions` annotation to let Cucumber know where to find the feature files and the step definitions.

    package com.testingbotdemo.selenium.cucumber.runners;
    
    import io.cucumber.testng.AbstractTestNGCucumberTests;
    import io.cucumber.testng.CucumberOptions;
    
    @CucumberOptions(
            features = "src/test/resources/features",
            glue = "com.testingbotdemo.selenium.cucumber.definitions"
    )
    public class TestRunner extends AbstractTestNGCucumberTests {
    }

## Step Definitions

Finally, we need to define the step definitions. This is the logic that converts the Gherkin syntax to actual code.

The code that we will use will interact with the [Driver class](https://testingbot.com#driver) we defined.

    package com.testingbotdemo.selenium.cucumber.definitions;
    
    import io.cucumber.java.After;
    import io.cucumber.java.Before;
    import io.cucumber.java.en.Given;
    import io.cucumber.java.en.Then;
    import io.cucumber.java.en.When;
    import org.openqa.selenium.By;
    import org.testng.Assert;
    import com.testingbotdemo.selenium.cucumber.drivers.TestingBotDriver;
    import org.openqa.selenium.WebDriver;
    
    public class StepDefinitions {
        private WebDriver driver;
    
        @Before
        public void setUp() {
            driver = TestingBotDriver.getDriver();
        }
    
        @Given("I open Google")
        public void i_open_google() {
            driver.get("https://www.google.com");
        }
    
        @When("I search for {string}")
        public void i_search_for(String query) {
            driver.findElement(By.name("q")).sendKeys(query);
            driver.findElement(By.name("btnK")).submit();
        }
    
        @Then("I should see results")
        public void i_should_see_results() {
            Assert.assertTrue(driver.getTitle().contains("Google"));
        }
    
        @After
        public void tearDown() {
            if (driver != null) {
                driver.quit();
            }
        }
    }

## Run Cucumber test

You can now run the Cucumber test:

    TESTINGBOT_KEY={..your-key..} TESTINGBOT_SECRET={..your-secret..} mvn test

The test will run on a remote TestingBot browser. Once the test has finished, you will be able to see the result, together with a video and logs in the TestingBot dashboard.

## Specify Browsers & Devices

To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field.

  ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg) Windows 11 › ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg) Chrome 139 

Loading environments...

Please wait while we load the available browsers and platforms.

    

## Testing Internal Websites

We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps.  
Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution.

The example below shows how to easily run a TestNG test with our Tunnel:

1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel:

    java -jar testingbot-tunnel.jar key secret

2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address.   
 Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel.

This way your test will go securely through the tunnel to TestingBot and back:

    package com.testingbotdemo.selenium.cucumber.drivers;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    import org.openqa.selenium.remote.RemoteWebDriver;
    import java.net.URL;
    import java.net.MalformedURLException;
    import java.util.HashMap;
    import java.util.Map;
    
    public class TestingBotDriver {
    
        public static WebDriver getDriver() {
            ChromeOptions options = new ChromeOptions();
            options.setPlatformName("WIN11");
            options.setBrowserVersion("latest");
    
            Map<String, Object> tbOptions = new HashMap<>();
            tbOptions.put("name", "Tunnel Cucumber Example");
            tbOptions.put("build", "build-1");
            options.setCapability("tb:options", tbOptions);
    
            try {
                return new RemoteWebDriver(new URL("http://localhost:4445/wd/hub"), options);
            } catch (MalformedURLException e) {
                e.printStackTrace();
                throw new RuntimeException("Invalid URL provided for TestingBot tunnel", e);
            }
        }
    }

## Run tests in Parallel

Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time.

You can run the same tests on all different browser configurations or run different tests all on the same browser configuration.   
 TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time.

To run a test on different browsers at the same time, you can run the same `mvn test` command multiple times in parallel, each with a different browser/capability environment variable.

For example, assuming you define the desired capabilities with environment variables:

    ChromeOptions options = new ChromeOptions();
    options.setPlatformName(System.getenv("CAPABILITY_PLATFORMNAME"));
    options.setBrowserVersion(System.getenv("CAPABILITY_BROWSERVERSION"));

Now you can run the same test on multiple browsers simultaneously:

    mvn test -DCAPABILITY_BROWSERNAME=chrome -DCAPABILITY_BROWSERVERSION=latest -DCAPABILITY_PLATFORMNAME=WIN11
    mvn test -DCAPABILITY_BROWSERNAME=safari -DCAPABILITY_BROWSERVERSION=latest -DCAPABILITY_PLATFORMNAME=SONOMA

### Queuing

Every plan we provide comes with a limit of parallel tests.   
 If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available.

## Mark tests as passed/failed

To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use the TestingBot [API](https://testingbot.com/support/api).

TestingBot has a [Java client](https://github.com/testingbot/testingbot-java) to facilitate interacting with the TestingBot API.

**Maven:**

    <dependency>
        <groupId>com.testingbot</groupId>
        <artifactId>testingbotrest</artifactId>
        <version>1.0.10</version>
    </dependency>

**Gradle:**

    implementation 'com.testingbot:testingbotrest:1.0.10'

Once you've included this client with your tests, you will be able to send back the test status and other meta-data to TestingBot:

    import com.testingbot.testingbotrest.TestingbotREST;
    import io.cucumber.java.After;
    import io.cucumber.java.Scenario;
    import java.util.HashMap;
    import java.util.Map;
    import org.openqa.selenium.remote.RemoteWebDriver;
    
    @After
    public void tearDown(Scenario scenario) throws Exception {
      TestingbotREST api = new TestingbotREST(System.getenv("TESTINGBOT_KEY"), System.getenv("TESTINGBOT_SECRET"));
      Map<String, String> data = new HashMap<>();
      data.put("success", scenario.isFailed() ? "0" : "1");
      data.put("name", scenario.getName());
      api.updateTest(((RemoteWebDriver) driver).getSessionId().toString(), data);
      driver.quit();
    }

## Other Java Framework examples

- [JUnit](https://testingbot.com/support/web-automate/selenium/java/junit)

JUnit is a unit testing framework for the Java programming language.

- [Parallel JUnit](https://testingbot.com/support/web-automate/selenium/java/parallel-junit)

By running multiple JUnit tests at the same time you can cut down on overall test time.

- [TestNG](https://testingbot.com/support/web-automate/selenium/java/testng)

TestNG is a framework similar to JUnit and NUnit, which supports some additional commands and features.

- [Selenide](https://testingbot.com/support/web-automate/selenium/java/selenide)

Selenide is a Java-based test framework, with a concise API for writing stable and maintainable UI tests.

### Looking for more help?

Have questions or need more information? Reach out via email or Slack.

[Email us](https://testingbot.com/contact/new)[Slack Join our Slack](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw)
