Introduction to the Problem
Most of the time when you need to write functional tests/end-to-end tests for web UI, you end up by using Selenium, which it can consider the de-facto tool in Java world for web UI testing. I am sure you've already used it for these kind of tests.
Fixing First Problem
To fix the first problem, the most easier solution you can think is using Docker containers and of course Docker compose since you can define and run multi-container Docker applications. So basically you define in docker-compose file, all the servers that you might need to run the tests so when you run tests you have all of them running and more important with a fixed version, so you can be sure that the tests are always run against a known/desired specific version of the servers, same JDK, ... and not depending on what is installed in developers/CI machine.
But this approach has one problem. You need to specifically run docker-compose up, docker-compose down. Of course you can automate this in your build script, which will solve the problem on CI environment, but if a developer wants to execute a test from IDE, let's say for debugging, then he needs to be aware of that fact.
And this is what Arquillian Cube solves. Arquillian Cube is an Arquillian extensions that uses docker-compose file to start and configure all the containers defined there, execute the tests and finally shutting down all of them. The good news is that since Arquillian works with JUnit (and TestNG and Spock), you can run the tests from the IDE without worrying about starting and stopping containers since Docker lifecycle is managed by Arquillian Cube.
So first part of the problem that is defining the test environment is fixed with Arquillian Cube. Let's see how to fix the second one.
Fixing Second Problem
Selenium project provides a Docker images with Selenium standalone or Selenium node with browser (Firefox or Chrome) and a VNC server installed.
So it seems a perfect fit to fix the problem of having to install browsers with a concrete version or concrete configurations locally since you can use a docker image with a browser configured for the tests.
New Problems When Using Docker for Testing
And that's cool, but it has some problems. The first one is that you need to create a docker-compose file specific for testing purposes, although this is not a bad thing per se, but it requires more management from dev part to maintain this file as well and of course repeat again and again in all the projects you want to use it, defining the browser to use and the VNC client image to get the recording for future inspection.
The second problem is the configuration of WebDriver. When running WebDriver against a remote browser, you need to set the location (IP) of the browser and configure the RemoteWebDriver accordantly with desired capabilities.
So again you have to write in all the tests the WebDriver configuration again and again. You can create a factory class that can be reused in all the projects, and it is good, but you still have one problem, some developers might use Docker machine so IP would not be static and might change every time, other might be using native Docker, and for example some phases of CI pipeline might run the tests against a remote fully environment like preproduction environment, so before executing tests you would need to specify manually the IP of container of Docker host.
And the third problem you'll get is that you need to instruct WebDriver to open a page:
The problem is that in this case the browser is inside the Docker infrastructre so you need to set the internal IP of the server container, so you don't only need to know the Docker host IP for connecting the remote web driver but also the internal IP of the server container to open the page in remote browser using the get method. And again this might be quite difficult to acquire in an automatic way.
But all these problems are solved when using the new integration between Arquillian Drone and Arquillian Cube.
Fixing New Problems
Arquillian Drone is an Arquillian extension that integrates Selenium WebDriver to Arquillian. This extension manages the configuration of the WebDriver so you don't need to repeat it in all your tests, and also the lifecycle of the browser.
So as you can see this pair of extensions seems a perfect fit for solving these problems. Drone takes care of configuration meanwhile Cube takes care of configuring correctly the Selenium/VNC containers and starting and stopping them.
As you might see, you don't need to worry about creating docker-compose file for testing purposes. You only need to create the one used for deploying, and Arquillian will take care of the rest.
The first thing to do is create a project with required dependencies. For this example we are using Maven, but you can achieve the same using other build tools.
Things important to notice is that you are using BOM definitions for setting versions of the components. Then we set Arquillian Standalone dependency because our test is not going to have @Deployment method since the deployment file is already created inside the Docker image used in the application. Finally Arquillian Cube and Arquillian Drone dependencies are added.
Next step is creating at src/test/resources a file called arquillian.xml which is used for configuring extensions.
You can see that:
- You need to specify the docker machine name where to start containers in case of using docker machine. If you are using native Docker then you don't need to set this attribute.
- You need to set a location relative to root folder of the project where docker-compose file is located. Note that you could use any other name.
And finally the test:
There are some interesting parts in this test.
- It is a standard Arquillian test in the sense it uses Arquillian runner.
- Uses @Drone injection mechanism provided by Arquillian Drone to enrich test with a WebDriver configured to connect to remote browser.
- Uses @CubeIp annotation to enrich test with the internal IP of the container helloworld. Since browser is running inside Docker host, we can use the internal IP for this purpose. Also it is important that you need to use the exposed port and not the bind port.
- Everything else is managed by Arquillian Cube like the start and stop of the Docker containers(helloworld in this case) but also the ones containing the browser and the VNC client. If you put a debug point inside test method, and then execute a docker ps on a terminal, you'll see that three containers are started, not just helloworld.
- If after running the test you inspect target/reports/videos directory you will find the video recording of the test.
When I look 'round, I only see outta one eye
As the smoke surrounds my head, the sauna (Stickin' In My Eye - NOFX)