First of all, why do we need them?
We are used to implement a feature, write some unit tests for it and just double check in the browser if everything is working as expected. In many cases this might work pretty nicely. But we might miss some opportunities!
Considering the time we spend clicking through the website and checking that our changes did not break some other functionality, just running UI tests saves a lot of time. If those tests are even running as part of a build pipeline, we can be pretty sure that we deliver working software.
Additionally, UI tests by nature reflect the users’ perspective. By writing them we change our point of view and look away from implementation details and look more closely on our main goals: enabling users to conduct all necessary interactions to get what they want. For example, the basic UI test for an online shop would add some items to the basket, checkout and assure that the order was submitted correctly. If this flow is working correctly, we make sure that the website is at least usable to make some money.
As functional and implementation details might change over time, UI tests should just assure the basic functionality and not check every possible edge case. Otherwise, we will spend a lot of time adjusting them to changed requirements. For more insights read Mike Cohn’s blog post about service layer testing.
Basic Setup
So let’s see what we have to do to get ready for our first UI test. In this example, we will use TestNG as test framework, but of course you can use any other testing framework as well. In the first place, we need to include Selenium and TestNG into our project, as well as a web driver manager. Make sure the version numbers are still the latest ones, as Selenium might otherwise not work with your latest browser version. Using Maven this might look like this:
github:7472e377ab611d2b48dc13b51d48fe3b
Hello World or rather Hello Google
So let’s write our first test. Therefore, we create a test class and a first method which sets up the Chrome driver, creates a WebDriver object and opens Google’s website:
github:599444df79a56ec9a00ddfbf23c9605f
Just try this out and see what happens. If you are lucky enough, your Chrome browser will open up and visit google.com. Nice, isn’t it? So let’s select the search field, enter an appropriate search term and see what Google does:
github:333e78d7165bac351e570d8d13eeaa6b
You might wonder why we can call submit on an element. That’s because the WebDriver will find the right form for us and submit it. Very handy, isn’t it? Of course, we can not only select elements by name, but also by id, class name, css selector, a partial link text, tag name or xpath expression. You can find explanations for all of them in the Selenium-WebDriver API Commands and Operations documentation.
Now let’s check if our company website is still the first search result. Therefore, we wait until the results page has loaded and select the first result to check if its link points to comsysto.com:
github:4515a1bb2caa2bec067981726dc0859e
As hopefully everything worked fine, we afterwards close the close the broser and quit the WebDriver connection by calling:
github:a2ee77f2fd0410cac9787b87381b2cbf
Now, lean back and watch the code work for you! Feels awesome, doesn’t it? Just let it rerun several times to get a feeling of how much time and effort you will save in the future. You can check out the whole source code of this example on github.
How to write beautiful tests
As Selenium is now doing all the annoying clicking and typing for us, we can entirely focus on writing beautiful test code. Therefore, we introduce an abstract test class and let all other test classes inherit from it. Inside the abstract test class we can setup the WebDriver before each test class and shut it down afterwards like this:
github:e07eac6b4e71cb2643618edaefd31fcf
As we might have to select the same elements in different tests, we will introduce one class for every page of our website and specify all possible interactions in there. Then our tests can call the page’s methods to perform all actions on that page. Now we don’t have to repeat ourselves and can keep our tests simple and clean. If you want to know more about this pattern, read Martin Fowler’s blog post about page objects. To ease the use of our page objects, we can introduce a fluent API and return the current or resulting page in each method. To get your code even cleaner, transform your selector strings into constants and get something similar to this:
github:841fe04ceb93a1d0d23398838e358e99
Adjusting the test run to your needs
As it might happen that our tests do not get what they are looking for, we set a timeout with the following lines of code:
github:3729aa1f466b80ea6ee40c2f1a895b63
Just set the TIMEOUT_IN_SECONDS constant to an appropriate amount for your website. We use something around 30 seconds, to make sure that the element is really not showing up.
Choose your browser
Regarding the browser you will use for your UI tests you can choose between several options. Beside popular browsers like Firefox, Chrome and Safari and unpopular ones like Internet Explorer ;), you can also choose some special ones, like the HtmlUnitDriver. It’s a pure Java solution and very fast, but as the engine behind is not used by any popular browser, your results might defer significantly. As HtmlUnitDriver has disabled JavaScript support by default, you need to call the constructor with ‘true’ as parameter or use the setJavascriptEnabled() function.
Another possibility is the Phantom browser. It’s a headless browser, which can be especially helpful when you are running your tests as part of a build process and doesn’t want to start heavy UI browsers.
As you might have noticed, we are using the webdrivermanager library of Boni García for this example. You can also go without it, but then you need to install drivers manually on your computer, which can get quite annoying.
TL;DR
UI tests can save you a lot of time and ensure software quality. To get life long happiness, use suitable libraries and make sure you write beautiful and maintainable code using abstract classes and page objects. Finding the right browser for your environment isn’t always easy, so don’t worry if you try and error for some time. So get your hands dirty!
You can check out the example code on github.
Learning more
For further information, have a look at SeleniumHQ and the Webdriver documentation.
If you have any questions or suggestions, feel free to comment