<- Back

In this article, I will explain how you can run tests in parallel. I am explaining it in the context of rest assured, but core concepts can be applied to any kind of testing.

Why to run in parallel

You can save lot of time by running tests in parallel.

How to run in parallel

RestAssured is a Java-based library for testing RESTful web services. To run RestAssured tests in parallel, you have several options:

  • Using TestNG: TestNG is a testing framework for Java that supports parallel testing. You can use the TestNG XML configuration file to configure parallel execution of RestAssured tests. You can configure the number of threads, classes, and methods to run in parallel.

  • Using JUnit: JUnit is another testing framework for Java that supports parallel testing. You can use the JUnit Parallel Computer to run RestAssured tests in parallel. You can also use the JUnit Suite to configure parallel execution of RestAssured tests.

  • Using Maven: Maven is a build automation tool for Java projects that can run tests in parallel. You can configure Maven to run RestAssured tests in parallel by specifying the number of threads to use for the test execution.

  • Using Gradle: Gradle is another build automation tool for Java projects that can run tests in parallel. You can configure Gradle to run RestAssured tests in parallel by specifying the number of threads to use for the test execution.

  • Using ExecutorService: You can also use the ExecutorService class in Java to run RestAssured tests in parallel. You can create a thread pool and execute the tests concurrently.

Here is an example of using TestNG to run RestAssured tests in parallel:


import io.restassured.RestAssured;
import org.testng.annotations.Test;

public class RestAssuredTest {

    @Test(threadPoolSize = 3, invocationCount = 6, timeOut = 10000)
    public void testRestAssured() {
        RestAssured.given().get("https://jsonplaceholder.typicode.com/posts/1").then().statusCode(200);
    }
}

Here is another example using Executor Service

import io.restassured.RestAssured;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class RestAssuredTest {

    public static void main(String[] args) {
        int numberOfThreads = 3;
        ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);

        for (int i = 0; i < numberOfThreads; i++) {
            executorService.execute(new RestAssuredTask());
        }

        executorService.shutdown();

        try {
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static class RestAssuredTask implements Runnable {
        @Override
        public void run() {
            RestAssured.given().get("https://jsonplaceholder.typicode.com/posts/1").then().statusCode(200);
        }
    }
}

Best practices for handling shared objects during parallel testing

When running tests in parallel, there is a possibility of shared objects being accessed concurrently by multiple threads, which can cause race conditions and other synchronization issues. To avoid these issues, you need to ensure that shared objects are accessed in a thread-safe manner.

Here are some best practices for handling shared objects during parallel testing with RestAssured:

  • Use ThreadLocal: ThreadLocal is a class in Java that allows you to store thread-local variables. ThreadLocal variables are unique to each thread and cannot be accessed by other threads. You can use ThreadLocal to store shared objects that are specific to each thread. For example, if you have a RestAssured test that requires an authentication token, you can store the token in a ThreadLocal variable.

  • Use synchronized methods: If you have shared objects that need to be accessed by multiple threads, you can use synchronized methods to ensure that only one thread can access the object at a time. Synchronized methods ensure that the thread that acquires the lock can access the shared object while other threads wait for the lock to be released.

  • Use concurrent collections: If you need to share data between threads, you can use concurrent collections such as ConcurrentHashMap, ConcurrentLinkedQueue, and ConcurrentSkipListSet. These collections are designed to be thread-safe and can be accessed by multiple threads concurrently.

  • Use immutable objects: If possible, use immutable objects for shared data. Immutable objects are thread-safe because they cannot be modified once created. If you need to modify the object, you can create a new instance with the updated value.

  • Avoid static variables: Static variables are shared by all threads and can cause synchronization issues. Avoid using static variables for shared data.

Here's an example of using ThreadLocal to store a shared authentication token:

import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import org.testng.annotations.Test;

public class RestAssuredTest {

    private static final ThreadLocal<String> AUTH_TOKEN = new ThreadLocal<>();

    @Test(threadPoolSize = 3, invocationCount = 6, timeOut = 10000)
    public void testRestAssured() {
        String authToken = AUTH_TOKEN.get();
        if (authToken == null) {
            authToken = getAuthToken();
            AUTH_TOKEN.set(authToken);
        }
        RequestSpecification request = RestAssured.given().header("Authorization", authToken);
        // perform rest assured test using the request
        request.get("https://jsonplaceholder.typicode.com/posts/1").then().statusCode(200);
    }

    private String getAuthToken() {
        // logic to get authentication token
        return "some-auth-token";
    }
}

In this example, we are using a ThreadLocal variable to store the authentication token. The get() method retrieves the token from the ThreadLocal variable. If the token is not present, the getAuthToken() method is called to retrieve the token, and it is stored in the ThreadLocal variable using the set() method. This ensures that each thread has its own copy of the authentication token and avoids race conditions.

Logging in parallel tests

When running tests in parallel, multiple threads will be executing test methods simultaneously. In order to ensure that Log4j messages from different threads don't interfere with each other, you can use Log4j's ThreadContext to associate a context with each thread.

Here's how to use Log4j with parallel tests in TestNG:

import org.apache.logging.log4j.ThreadContext;

@BeforeMethod
public void setup() {
    ThreadContext.put("testName", testName.getMethodName());
}

logger.info("Starting test {}", ThreadContext.get("testName"));

Here's how to use Log4j with parallel tests in TestNG:

@Before
public void setup() {
    ThreadContext.put("testName", testName.getMethodName());
}

@After
public void teardown() {
    ThreadContext.clearAll();
}

logger.info("Starting test {}", ThreadContext.get("testName"));

Web development and Automation testing

solutions delivered!!