Selenium Considerations | C#
Arguably the most used web testing library today, almost every automation test engineer working on web applications has used Selenium at one point or another. Selenium has a well documented set of best practices, and I’d like to take a deeper look at some of these best practices to offer a more detailed understanding of why they are recommended. For those of you just starting out in automation, or even if you have run into some of the issues mentioned below, I hope to provide you some good ideas for how to tackle common Selenium challenges.
Avoiding sleep
Let's say that we are testing a React page. It’s a login page, and has an external login option (for example, sign in via Google). We have been tasked with testing to ensure this external provider button works. We begin writing the test case but notice that this button can take anywhere from two seconds to five seconds to appear on the page. No worries, we simply add a five second Thread.Sleep and go on with our day right?
One problem with this scenario is that if our UI developers add a performance fix the very next day to make this button load in 500ms then suddenly we’ve blown out the test execution time for seemingly no reason. The other problem is that Selenium has actually already resolved this problem for us..
If you’re using the C# bindings of Selenium, check out the ImplicitWait found on the WebDriver.
Effectively, the ImplicitWait is just Selenium polling every 100ms or so to wait for the element to be visible when FindElement is used. This is ideal as it won’t always need to wait the maximum specified time, like in Thread.Sleep.
Idempotency is key
This means that I should be able to run a single test multiple times and get the exact same results. I should never, ever have to run the previous test so that the test data is created. Alternatively, I should never build tests in such a way that they must be run in a particular order.
When diagnosing test failures, the last thing I want is to be led down a completely separate path because five of my tests are failing instead of one. If tests rely on each other, all it takes is one failure to start a domino effect.
Add your own functionality
In every test framework I have seen, extensions have been made to Selenium to ensure it fits the requirements. I encourage everyone to go through the documentation, read through the GitHub repo and familiarize yourself with the inner workings of the C# bindings of Selenium. Knowing exactly how Selenium works can greatly assist when diagnosing failures with your own tests.
With React and other JS frameworks becoming more prevalent, it poses a challenge to those writing the web tests. Selenium cannot just find a React component by the text it contains out of the box.
I have found that by writing these extension methods my own understanding of Selenium has grown exponentially. Digging through the GitHub files to find out what an ISearchContext is to actively monitoring the Slack channel has been an excellent learning experience.
Finally, a word on flakiness
A major pain to diagnose, 'flakey tests' give the test engineer zero confidence that a legitimate bug can be found. A flakey test is simply a test that randomly fails once every x executions without making any changes to the code. If the tests fail at the drop of a hat, how can we trust them?
Flakey tests can be caused by a number of things. Added a new asynchronous call in the background? Accidentally deleted one of your testing users from the DB? Trying to locate an element and they've gone and changed the id?
Using ImplicitWait can help manage asynchronous waits, but only to an extent, and only if you're using FindElement. For page loads, I would recommend using the PageLoad property (shown in the screenshot above). There is also an option to set Selenium's idea of what a 'finished' page load is. This can be configured as shown below.