NashTech Insights

Selenium Testing With Test Containers And CI/CD Integration

Deepansh Gupta
Deepansh Gupta
Table of Contents

Selenium is one of the most widely used browser automation tool out there. Using Selenium, any front end application can be tested with automation. This powerful tool however requires few things in your system so it can run your automated test cases. You need to add dependencies and configurations in each system where you want to run your selenium tests. This setup can take some time and increase errors. Here comes test containers to help us with these dependencies.

What are Test Containers?

Test containers is Java library that provides special instances for your selenium tests to run. These containers are not restricted to running selenium tests, but can also be used for database applications, messaging queues or anything that can run in a docker container.

Test containers can also be used to create images of our web browsers so that our selenium tests can run in a freshly built image. Created docker containers will have a life cycle for the duration of your selenium tests and will be torn down once the execution has been completed.

Why Test Containers?

Test containers can improve your overall coverage and quality of tests. Here are few reasons why you should also be using test containers in your projects:

  • Faster test execution: With more isolated environment creation and deletion, test containers make your tests run faster. It also helps with detecting bugs earlier.
  • Testing in multiple environment and configurations: With test containers, we have the option to run our tests in multiple environments and configurations. This ensures that your code is compatible with all your required operating system configurations.
  • Integration testing execution: Test containers facilitate your tests and their corresponding dependencies to run within the same container to ensure that your integration tests are executing as per expectation.

Overall test containers can streamline your tests and help you deliver your tests much faster.

Benefits of using test containers with selenium

Test containers’ official documentation provides us with the benefits that come with using test containers and selenium together

  • Since a new browser image is created for each test, these containers make sure that the test run in a clean image which is independent of automatic browser upgrades or user changes.
  • Only installation you need is a working docker and your test suite. You do not need to have a specific environment or browser setup to run your test suite.
  • A clean browser image ensures security as there is no cookie leakage or cached data.
  • Test containers are fully compatible with Selenium 3 and 4 tests for Chrome and Firefox. Selenium 4 also supports Edge browser.
  • No more compatibility issues between browser and Selenium API.
  • Test Containers also has the provision to record your tests.

All these features of test containers help our selenium tests to run faster, with more accuracy. These also help with reducing overall cost of creating and maintaining these tests in the long run.

Cross browser testing is another great area where test containers help our automated tests. When writing automated tests for any front end application, we want to test those with as many browsers as we can. This is not easily achievable if you do not have a container setting up your test environments for each set of browser combinations.

How to use Test Containers in your Selenium tests

Since Test Containers start a docker containers for our tests, we have some pre-requisites that we need to follow if we want to use them with our Selenium tests:-

  1. JAVA 8 or higher
  2. Docker installed in our machine

You can use a testing framework as well to write your tests properly. For this blog, we will be using TestNG and make use of its annotations with our Selenium tests. Since our main focus for this blog is to see how we can automate web applications, we will only look at the Selenium docker image. You can also look at other excellent support that Test Containers provide with respect to docker images.

Dependencies required

Add the following maven dependencies to your pom.xml file. You can check out the latest versions for the same from maven central repository.

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
    <version>1.17.6</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>selenium</artifactId>
    <version>1.17.6</version>
</dependency>
<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.1.0</version>
    <scope>compile</scope>
</dependency>

You can remove scope as test depending on your need. If you do add it, keep in mind that your test should reside in src/test/java folder location.

Use BrowserWebDriverContainer class

For this demo project, we have used chrome as our browser so the docker image and configurations are set for the same. You can replace with your desired browser in the below code. After completing our base class, this is what it looks like:-

public static String chromeImg = "selenium/standalone-chrome-debug"; 
public static String chromeImgVersion = "3.141.59";
public static BrowserWebDriverContainer<?> chromeContainer = null;  //class to bring up Selenium TestContainer

//Start the test-container
@BeforeSuite(alwaysRun = true)
public static void initialise(){
    DockerImageName dockerImage = DockerImageName.parse(chromeImg).withTag(chromeImgVersion);
    chromeContainer = new BrowserWebDriverContainer<>(dockerImage).withCapabilities(new ChromeOptions());
    chromeContainer.start(); //Start the selenium container
}

@AfterSuite(alwaysRun = true)
public static void tear(){
    chromeContainer.close(); //release all the resource
    chromeContainer.stop(); //shut down the container
}

Let us see what we are doing in the above code:-

  1. We have passed chrome docker image in string variable chromeImg and the image version in chromeImgVersion.
  2. Next we have created an object of class BrowserWebDriverContainer as chromeContainer. This is to bring up our Selenium Test Container.
  3. Using TestNG @BeforeSuite annotation, we have created an initialise() method to start our browser . In the method, we have used DockerImageName class to create an object dockerImage and then use parse() method to parse docker image name as a string. withTag() method takes in the version for our docker image that we set in above variable.
  4. Now we are setting our chromeContainer object by passing dockerImage object and using withCapabilities() method to select our browser option. In this case, we have chromeOptions(). You can also set video recording capabilities for your tests in this step using the following steps mentioned in official documentation.
  5. Final step to start our container is to use start() method on our object.
  6. @AfterSuite annotation is also used with tear() method to stop our docker container once all the tests have run.

Now that our base class is completed, let us have a look at your test class where our actual tests will be written.

@Test
public void openUrl() {
    RemoteWebDriver driver = Base.chromeContainer.getWebDriver();
    driver.get("https://www.google.com/");
    System.out.println("Opened url");
    System.out.println("URL : " + driver.getCurrentUrl());
}

In the above @Test annotated method, we simply want to open a url. To do that , we need a driver object. Normally we write Webdriver driver = new ChromeDriver() to create our driver object, but we cannot use that with our Test Container test. Since Selenium server is running on our docker container, we will need to use RemoteWebDriver class.

You can now run your testng.xml file by setting your desired configurations. You can also put debug point where your selenium container starts and check if your container is running from your terminal.

Integration with CI/CD pipeline

Moving quality features to your production environment is a necessity now. That is where the concept of CI/CD comes into picture. You can automate your delivery process much faster with CI/CD. This reduces time to deploy significantly. The process of continuous integration/ continuous delivery does need its own set of tools to facilitate this automation.

Integrating CI/CD with your project would require a separate tool most of the times. For this demo, we will be looking at one such tool : Github Actions. You can also use Jenkins or Gitlab CI but the reason we have chosen Github Actions is because it is easy to use and free.

If we were not using Test Containers for our project and running docker containers ourselves manually, then we would have a more complicated CI/CD integration, but since Test Containers does that for us, we do not need to worry about manually triggering docker related things anymore.

With not much configuration changes to do , let us look at how we can create our first github action file and integrate it with our Test Container project we created above.

Creating a workflow

A workflow is essentially a process or a set of processes in the same file that helps to automate a particular task. The task can be related to build, deploy or any options out of the vast list that Github Actions provide.

There are some basic steps that you can take to create a new workflow directly from your Github repository:-

  1. Go to your repository and select “Actions” tab.
  2. Click on “new workflow”. You should see a screen with “Choose Workflow” heading and many options to select from.
  3. For this blog since we created a java with maven project , we will be “Java with Maven” option
  4. You should see a file which you can edit. This is your workflow file. Add the following code in your workflow file and commit the same to your repository.

name: Java CI with Maven
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run TestNG Tests
  uses: actions/setup-java@v3
  with:
    java-version: '11'
    distribution: 'temurin'
    cache: maven
- name: Build with Maven
  run: mvn test

To explain the above workflow :-

  1. This is a workflow named “Java CI with Maven”. The workflow is triggered by two events: push and pull request, but only for the “master” branch.
  2. The workflow consists of one job named “build” which runs on the latest Ubuntu image provided by GitHub.
  3. The “build” job has three steps:
    • The first step uses the actions/checkout action to checkout the code from the repository.
    • The second step uses the actions/setup-java action to set up a Java environment with version 11 using the Temurin distribution. It also enables caching of the Maven dependencies for faster builds.
    • The third step runs the mvn test command to build the project and run the TestNG tests.

In summary, this workflow sets up a Java environment with Maven and runs the TestNG tests when a push or pull request is made on the “master” branch.

So this is the complete process of how you can start creating your selenium tests with test containers and integrate it with a basic CI/CD tool like github actions

Deepansh Gupta

Deepansh Gupta

Deepansh is a Quality Analyst with 3+ years of experience in both manual and automation testing. He has worked on various tech stacks which include technologies such as Selenium, RestAssured, Gatling among others.

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

%d bloggers like this: