Notice: Undefined index: height in /var/www/ on line 27
code –

code (2)

Stable Selenium Tests

Let’s face it, they are slow, brittle and expensive to maintain. But then again there is no real replacement for making browser-based end-to-end tests. And as long as you keep the system test suite small, isolated and concise there shouldn’t be much to maintain.

On code testing code

Let’s keep it in mind that for any good system should include the following type of testing

  • many unit tests to test that the code honors its contact, how else can you know?
  • some integration tests for important flows through integrated components functionally
  • few system tests for important end-to-end flows, this tests that the system stands up
  • little manual testing using the human-eye for things that are hard to detect like usability

For this post i’m going to focus on the few system tests and how to make them as stable, readable and simple as possible. If you have heard of page object pattern, data-tags and selenium grids then this post is redundant to you. But if it is news for you then please read on.

They are the three most important patterns to follow if you’re going to make selenium tests. Here’s what they do and why they help.

Page Object Pattern and data tags

Single purpose classes that are responsible to act as an API for a test that is responsible for resolving WebElement using CssSelectors, ids or classes. This makes for readable tests. By using a tag called data-test that holds an unique identifiera that never changes we can lock the test onto that tag no matter which type of element or classes it has. This is preferrable to relying on either XPath, ids or classes which are subject to change if the page changes. This will alleviate tests breaking because someone on the frontend refactors CSS classes, and leave the breakages that means something is missing, invisible or immovable.


This kind of page object contains the page-specific element names and maps them the variabler that makes sense for the content. The suoerclass takets care of initializing @FindBy-annotated variabler lazily, meaning it is evaluated upin accessing the element. Something like

A simple grid

A selenium grid is a server that runs selenium tests as a service. There are naturally many cloud providers for this use case but there are some FOSS disruptors in that space asswell. I have especially taken heart to selenoid, that spawns docker containers containing insividual isolated browsers in a headless way that is VERY suitable for running Quick system tests upon a new deploy.

Setup a selenoid grid locally by using this Vagrantfile if you like, it will speed up and automate the process, i’m going to assume it is available from your localhost moving on.

A Java Project

Include the following dependencies in your pom.xml, build.xml or build.gradle to run selenium-java-remote using JUnit 4. We’re going to stay away from large frameworks and simply run Selenium Tests as a regular unit-test. Use whatever loggning library you like and replace my println, logging is not the focus of this article. 😉

Here’s a tiny that initializes the Page Objects and creates the remote webdriver.

Any JUnit test must extend this class and will initialize a remote webdriver per each test in this case. This can also be used to run as many test-methods in parallel as there are concurrent containers in the grid. This is when Selenoid shines the brightest, because it will create a lightweight container for each test method making for awesome idempotent and isolated tests. The TestBase will parse if a test has failed and put a recording of it into the target folder if you’re running maven.

This results in small, stable and readable tests such as this one.

I hope that helps you running better, faster and more stable Selenium-based test at all levels!


New Blog

Warning: filemtime(): stat failed for /var/www/ in /var/www/ on line 30

Notice: Trying to get property of non-object in /var/www/ on line 31

Notice: Trying to get property of non-object in /var/www/ on line 31

Notice: Trying to get property of non-object in /var/www/ on line 33

Notice: Trying to get property of non-object in /var/www/ on line 34

Notice: Trying to get property of non-object in /var/www/ on line 35

Notice: Trying to get property of non-object in /var/www/ on line 37

Notice: Trying to get property of non-object in /var/www/ on line 38

Notice: Trying to get property of non-object in /var/www/ on line 39


Not that i really had an old one, but it was time to make myself one. Especially considering that fiber was finally installed into our house. Free access to the internet highway means ye olde server actually doing something. So why not a blog, about code and life, at 03:30 AM in the morning. What could possibly go wrong? I most likely misconfigured something along the way.

Anyway. The point of this blog is to keep my code, stories, scripts, failed bread-recipes, some kind of curriculum and misconfigured servers in the same place.

Short introduction.

I’m a father, husband, baker, cyclist, snowboarder, geek and last but not neccessarily least a software engineer/developer/architect. I consider titles to be irrelevant, whoever writes the code really gets the job done. I’m going to keep short on most parts private, shielding my family somewhat from the fierce domain of the intertubes. But professionally i can keep talking.

My profession is first and foremost about writing code. I like functional programming, Linux, the JVM, continuous integration, hosting my own servers and stuff that categorizes as hometech.

In that area there’s more than a few Raspberry Pi’s, one in particular powering a (not yet put inside a box) MagicMirror, which i’m very fond of at the moment.


I’m going to make a habit of sharing code snippets i’m particularly fond or proud of, so i’ll get started right away.

Here’s a piece of bash that shows the current git branch (if any), you are on directly on your REPL, give it a spin!


Show branch name in terminal


Here’s my GitHub btw, seems like GitHub stopped answering when the site bombarded them with requests while configuring.