Acceptance testing at synyx – Part 2
In the first part of the series I gave some reasons why to do acceptance testing (or webtests) as well as a rough overview how we do it at synyx. This part is rather technical and describes how to use Seleniums RemoteWebDriver to control browsers on a remote host.
Running browsers elsewhere - Selenium GRID
One important thing for me is that the browsers that are used to execute the webtests should not run on the same host as the tests. This way we can minimize setup for the tests on the developers machine. Also, the machine running our CI-System Jenkins is a headless server where no browsers can be installed. Therefore we also need the remoting capability for Jenkins.
And another important argument for running browsers on a remote host is that probably not all browsers you want to run your tests on can be installed on a developers machine. For example my unix machine refuses to run Internet Explorer ;-).
So in my opinion the best choice to execute tests is using Seleniums RemoteWebdriver.
If you are familiar with Selenium you know that in order to run your test in a browser you usually instanciate the correct WebDriver for it (e.g. FirefoxWebDriver to run a Firefox). But there is also RemoteWebDriver that can be used to steer browsers on some other host. So this RemoteWebDriver acts like a proxy, talks to a remote-service called selenium-server using HTTP. Then selenium-server actually controls the browser. See Seleniums documentation for further details.
As mentioned you have to have a selenium-server instance to use RemoteWebDriver. Selenium-server can run in standalone-mode or - if you want to scale up - as grid with a hub and many nodes. In this case you have one hub which only matches requested capabilities and delegates clients to existing hosts on selenium nodes.
The following graphic shows you how a setup using Selenium Grid (hub and nodes) could look like:
For now you could just download selenium-server and run it the way described here using
java -jar. To set up the selenium-hub and selenium-server in a reliable way please wait for the next part of the series where I describe how to do this for windows and unix systems.
Requesting a browser from the grid
Once here is a server running you are able to request a browser from it by instanciating RemoteWebDriver with the URL of it. In addition you have to describe the browser you want using the class
The following code snippet shows how to request a chrome version 20 on any operating system from a selenium-server listening to
DesiredCapabilities cap = new DesiredCapabilities("chrome", "20", Platform.ANY); // url of selenium-hub/server URL url = new URL("http://localhost:4444"); WebDriver driver = new RemoteWebDriver(url, cap); driver.open(targetSystemUrl); driver.findElement(By.id("number")).sendKeys("42"); ...
Execute tests with different browsers
In order to be able to execute the same test in many browsers we decided to read browser-capabilities from a .properties file instead of defining them hardcoded within the test classes. The name of the file can be handed to the test as system property to be able to control which browser to be used by adding
-DbrowserProperties=firefox.properties to the build commandline.
String fileName = System.getProperty("browserProperties"); Properties p = loadProperties(fileName); DesiredCapabilities c = new DesiredCapabilities( p.getProperty("browser.name"), p.getProperty("browser.version"), p.getProperty("browser.platform") );
I use this approach to bind the maven-surefire-plugin multiple times to the test lifecycle phase: once for each browser.
<plugin> <groupid>org.apache.maven.plugins</groupid> <artifactid>maven-surefire-plugin</artifactid> <version>2.12</version> <executions> <execution> <id>default-test</id> <phase>test</phase> <goals><goal>test</goal></goals> <configuration> <systempropertyvariables> <browserproperties>chrome.properties</browserproperties> </systempropertyvariables> <reportnamesuffix>chrome</reportnamesuffix> </configuration> </execution> <execution> <id>test-firefox</id> <phase>test</phase> <goals><goal>test</goal></goals> <configuration> <systempropertyvariables> <browserproperties>firefox.properties</browserproperties> </systempropertyvariables> <reportnamesuffix>firefox</reportnamesuffix> </configuration> </execution> </executions> </plugin>
An alternative to this could be to wrap the configuration within Maven profiles so that you can control which browsers should be used by
mvn test -Pfirefox and so on.
Since the test-code that reads the properties has defaults that make sense, it’s still also possible to execute the test using the IDE of your choice. For example simply default to requesting a chrome on any platform.
It worked out pretty well to have the infrastructural code within an abstract baseclass for all tests. This class uses
@BeforeClass to read needed capabilities from a properties-file, set up
RemoteWebDriver and point it to the system under test. Of course something like a JUnit Rule would also work.
Either way the actual tests don’t have to care about how the WebDriver they use is instanciated: They just use the baseclasses
getDriver() and execute the real testing-code.
In the next part I will show you how the Selenium Grid can be set up in good way so that you can make your local system administration happy \o/. So again… stay tuned.