docker-container-test-header

Selenium WebDriver – How To Run Automated Tests Inside A Docker Container

Overview:

Testautomationguru already has few docker and selenium related articles which talks about setting up the dockerized selenium grid.

  1. Setting up Dockerized Selenium grid.
  2. Managing Dockerized Selenium Grid using Arquillian cube.
  3. Setting up Dockerized Selenium grid in AWS / Cloud using RancherOS

Even if we have a selenium grid, we still need a host to run our tests – ie.. a host is required to run your maven command/ant/some batch file to execute the tests – so that test could talk to remote grid to send the WebDriver related instruction. In this article, we will see how we could use a container (as a host) for running our tests.

Challenges In Test Execution:

We already have simplified our selenium grid set up using docker using the above articles. But we still face few challenges. Your tests still have few dependencies to run them!

  • Test depends on specific version of java (like java 8)
  • Host should have maven or Ant or Gradle or other build tools installed
  • Tests depend on number of 3rd party jar files and other files like csv etc.
  • Tests depend on few jar files which are not part of maven repo!!
  • Remote slaves need to be set up with the build tools, java and any dependent jar files to execute the tests.

Managing these dependencies & Setting up remote slaves are time-consuming for big projects.

We will see how docker could help us here!!

Sample Test:

To show a demo, I am creating a simple maven project. I add the selenium-java & testNG dependencies.

<dependencies>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.11</version>
        </dependency>
</dependencies>

I add the below page object.

  • A Google Page Object which searches for a string and return search results
public class GooglePage {

    private final WebDriver driver;
    private final WebDriverWait wait;

    @FindBy(name = "q")
    private WebElement searchBox;

    @FindBy(css = "input.lsb")
    private WebElement searchButton;

    @FindBy(className = "rc")
    private List<WebElement> searchResults;

    @FindBy(id = "foot")
    private WebElement footer;

    public GooglePage(final WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
        this.wait = new WebDriverWait(driver, 30);
    }

    public void goTo() {
        this.driver.get("https://www.google.com");
    }

    public void searchFor(String text) throws InterruptedException {
        this.searchBox.sendKeys(text);
        wait.until(ExpectedConditions.elementToBeClickable(this.searchButton));
        this.searchButton.click();
        wait.until(ExpectedConditions.presenceOfElementLocated(By.className("rc")));
    }

    public List<WebElement> getResults() {
        return this.searchResults;
    }

}

A corresponding TestNG Test would be as shown here.

  • The test searches for ‘automation’ and checks if the search results count is at least 10.
public class GoogleTest {

    private WebDriver driver;
    private GooglePage google;

    @BeforeTest
    public void setUp() throws MalformedURLException {
        DesiredCapabilities dc = DesiredCapabilities.chrome();
        driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), dc);
        google = new GooglePage(driver);
    }

    @Test
    public void googleTest() throws InterruptedException {
        google.goTo();
        google.searchFor("automation");
        Assert.assertTrue(google.getResults().size() >= 10);
    }
    
    @AfterTest
    public void tearDown() throws InterruptedException {
        driver.quit();
    }    

}

Now You could simply execute the test,

  • Using maven, mvn clean test
  • Directly in the command line   java -cp mytest.jar org.testng.TestNG -testclass org.testautomationguru.test.GoogleTest

If I need to execute my tests using Jenkins in a remote slave, I need to ensure that my remote machine also has  java, maven etc. If the test depends on few jar files which are not part of maven repo, We need to ensure that it is copied to the appropriate remote local maven repo.  Basically – you need to set up entire dependencies in each machine for your tests to execute!  A lot of manual work!!

Dockerfile Maven Plugin:

Maven has a dockerfile plugin which nicely integrates docker and maven. It automates docker image build process in maven. By issuing a maven command, it creates a docker image based on the given Dockerfile in your project.

My project looks like this.

container-proj

To use the plugin, I add the below dependency in the maven pom file.

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>dockerfile-maven-plugin</artifactId>
    <version>1.3.5</version>
    <executions>
        <execution>
            <id>default</id>
            <goals>
                <goal>build</goal>
                <goal>push</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <repository>vinsdocker/containertest</repository>
        <tag>googletest</tag>
    </configuration>
</plugin>

My Dockerfile is as shown below. I create a single jar (container-test.jar) with all the dependencies by using maven-assemply-plugin.

Dockerfile:

FROM openjdk:8-jre-slim

# Add the jar with all the dependencies
ADD  target/container-test.jar /usr/share/tag/container-test.jar

# Command line to execute the test
ENTRYPOINT ["/usr/bin/java", "-cp", "/usr/share/tag/container-test.jar", "org.testng.TestNG", "-testclass", "com.testautomationguru.container.test.GoogleTest"]

When I issue the below command, it creates a jar with all the test dependencies and also creates a docker image.

mvn clean package

dockerfile-maven-build

It builds a new docker image which could be accessible using vinsdocker/containertest.

Now the docker image has been built with all the dependencies. An entrypoint has also been added – it means whenever you create a container (an instance of the docker image), it starts executing the test.

In my remote slave, I need to issue only below command – docker run vinsdocker/containertest:googletest

sudo docker run vinsdocker/containertest:googletest
Aug 27, 2017 4:06:05 AM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: OSS
Browser launched and navigated to Google
automation - entered for search
Search button clicked
Results appeared
Results Count : 11

===============================================
Command line suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================

I explicitly added few comments in the page object for better understanding.

Summary:

Docker not only helps us in setting up the selenium grid – but also simplifies managing test dependencies. Maven creates a new docker image as part of maven build process by using the given Dockerfile. Once the image is built, any machine with docker can execute the test!  It saves a lot of manual work in setting up the remote slave for execution.

 

Happy Testing & Subscribe 🙂

 

Share This:

Categories: Articles, CI / CD / DevOps, Docker, Selenium