---
title: Run parallel Selenium tests with Java and JUnit
description: Cross browser parallel testing with Java and JUnit. Run multiple tests
  concurrently.
source_url:
  html: https://testingbot.com/support/web-automate/selenium/java/parallel-junit
  md: https://testingbot.com/support/web-automate/selenium/java/parallel-junit.md
---

# Speed up JUnit tests by running them in parallel

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

## Dependencies

Add the following dependencies to your project. The example below uses `commons-io` for saving screenshots to disk:

**Maven (pom.xml):**

```xml
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>4.33.0</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.16.1</version>
</dependency>
```

**Gradle (build.gradle):**

```gradle
implementation 'org.seleniumhq.selenium:selenium-java:4.33.0'
testImplementation 'junit:junit:4.13.2'
implementation 'commons-io:commons-io:2.16.1'
```

## Helper class needed to run JUnit tests in parallel

```java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.junit.runners.Parameterized;
import org.junit.runners.model.RunnerScheduler;

public class Parallelized extends Parameterized {

    private static class ThreadPoolScheduler implements RunnerScheduler {
        private ExecutorService executor;

        public ThreadPoolScheduler() {
            String threads = System.getProperty("junit.parallel.threads", "16");
            int numThreads = Integer.parseInt(threads);
            executor = Executors.newFixedThreadPool(numThreads);
        }

        @Override
        public void finished() {
            executor.shutdown();
            try {
                executor.awaitTermination(10, TimeUnit.MINUTES);
            } catch (InterruptedException exc) {
                throw new RuntimeException(exc);
            }
        }

        @Override
        public void schedule(Runnable childStatement) {
            executor.submit(childStatement);
        }
    }

    public Parallelized(Class<?> klass) throws Throwable {
        super(klass);
        setScheduler(new ThreadPoolScheduler());
    }
}
```

Below is a JUnit Test example, which uses the above helper class to run the test in parallel.

```java
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.RemoteWebDriver;

@RunWith(Parallelized.class)
public class JUnitParallel {
    private String platform;
    private String browserName;
    private String browserVersion;

    @Parameterized.Parameters
    public static LinkedList<String[]> getEnvironments() throws Exception {
        LinkedList<String[]> env = new LinkedList<>();
        env.add(new String[]{"WIN11", "chrome", "latest"});
        env.add(new String[]{"WIN11", "firefox", "latest"});
        env.add(new String[]{"WIN11", "MicrosoftEdge", "latest"});

        // Add more browser configurations here

        return env;
    }

    public JUnitParallel(String platform, String browserName, String browserVersion) {
        this.platform = platform;
        this.browserName = browserName;
        this.browserVersion = browserVersion;
    }

    private WebDriver driver;

    @Before
    public void setUp() throws Exception {
        String key = System.getenv("TESTINGBOT_KEY");
        String secret = System.getenv("TESTINGBOT_SECRET");
        String hubURL = "https://" + key + ":" + secret + "@hub.testingbot.com/wd/hub";

        MutableCapabilities options = new MutableCapabilities();
        options.setCapability("browserName", browserName);
        options.setCapability("browserVersion", browserVersion);
        options.setCapability("platformName", platform);

        Map<String, Object> tbOptions = new HashMap<>();
        tbOptions.put("name", "Parallel JUnit Test");
        tbOptions.put("build", "build-1");
        options.setCapability("tb:options", tbOptions);

        driver = new RemoteWebDriver(URI.create(hubURL).toURL(), options);
    }

    @Test
    public void testSimple() throws Exception {
        driver.get("https://www.google.com");
        String title = driver.getTitle();
        System.out.println("Page title is: " + title);

        File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        try {
            FileUtils.copyFile(srcFile, new File("Screenshot.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @After
    public void tearDown() throws Exception {
        driver.quit();
    }
}
```

Run the tests with `mvn test`. Note that the Maven Surefire plugin only picks up test classes whose names match `*Test`, `Test*`, `*Tests` or `*TestCase` by default. The example class above is named `JUnitParallel`, so either rename it (for example `JUnitParallelTest`) or add an explicit `<includes>` entry to the Surefire configuration, otherwise `mvn test` will run zero tests.

The number of parallel threads is controlled by the `junit.parallel.threads` system property (default `16` in the helper class above). Set this to match the number of parallel sessions allowed on your TestingBot plan to avoid queuing, for example `mvn test -Djunit.parallel.threads=5`.

## 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 JUnit test with our Tunnel:

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

```bash
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:

```java
@Before
public void setUp() throws Exception {
    MutableCapabilities options = new MutableCapabilities();
    options.setCapability("browserName", browserName);
    options.setCapability("browserVersion", browserVersion);
    options.setCapability("platformName", platform);

    Map<String, Object> tbOptions = new HashMap<>();
    tbOptions.put("name", "Parallel Tunnel Test");
    tbOptions.put("build", "build-1");
    options.setCapability("tb:options", tbOptions);

    driver = new RemoteWebDriver(URI.create("http://localhost:4445/wd/hub").toURL(), options);
}
```

## 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 need to use our [API](https://testingbot.com/support/api).

TestingBot has a [Java client](https://github.com/testingbot/testingbot-java) for using the TestingBot API.

**Maven:**

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

**Gradle:**

```gradle
implementation 'com.testingbot:testingbotrest:1.0.10'
```

Once included with your tests, you can send back test status and other meta-data to TestingBot:

```java
import com.testingbot.testingbotrest.TestingbotREST;
import org.junit.After;
import org.openqa.selenium.remote.RemoteWebDriver;
import java.util.HashMap;
import java.util.Map;

@After
public void tearDown() throws Exception {
    TestingbotREST api = new TestingbotREST(System.getenv("TESTINGBOT_KEY"), System.getenv("TESTINGBOT_SECRET"));
    Map<String, Object> data = new HashMap<>();
    data.put("success", "1");
    data.put("name", "My Test");
    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.

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

Run tests with TestNG and BDD Cucumber.

### Looking for more help?

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

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