Mistakes – What Are You Waiting For?

Mistakes – What Are You Waiting For?

Mistakes that make you facepalm

Whether you write tests, write frameworks or both, one thing you are no doubt going to have to do at some point is have some kind of wait in your code. You might wonder why something so seemingly simple deserves its own article, but hopefully by the end of this, you’ll realise that waiting at any point in code can cause quite the headache.

When I first started writing tests, before I was involved in anything else, I’d be working on tests that dealt with front end applications that weren’t exactly the most efficient of designs. Often controls would take a while to become useable or pages would take a while to update, so it would only be natural to want to put waits in my test to deal with this. The trouble is, my go to solution for this would be to use the infamous Thread.Sleep, and just pass in a few seconds at a time. At the time, this seemed completely harmless, it’s an easy call to make with no overhead and it means I can be sure that by the time the call to Sleep has finished, my application will be ready for the next line in the test.

The trouble is that even just one Thread.Sleep in each test soon adds up. If you picture even just one second wait in each test, and having one thousand tests in your test suite, which isn’t that many if you’re in a large company with many teams, then straight away you have one thousand seconds spent just waiting. 17 minutes. Now that might not sound like much, but let’s face it, one second once in a test is on the low end.

It’s not uncommon to place tests upwards of ten or twenty seconds depending on where you’re using it, for example waiting on a modal loading screen to disappear. But the trouble with that is, Thread.Sleep doesn’t care whether your loading screen finishes in two seconds or even if it takes longer than the ten seconds you’ve told it to wait, it will only wait as long as it’s told then your test will resume. Which is bad news for the latter, but it’s just a big waste for the former. If your test only needed to wait for two seconds, now you’re just sat there for eight seconds doing nothing but adding unnecessary time to your test.

But there is a solution to this. And it’s all down to the fact that when it comes to automation, a wait is never just a wait. There are two different kinds of wait, Implicit and Explicit waits. Implicit waits are the ones we’ve been discussing up until now, and they are the ones that are so easily overused. They aren’t all evil and they have valid uses, and sometimes you just can’t get around having to use them, but for the most part, you should try keeping the use of implicit waits to a minimum.

The trouble is, while it’s easy to say to avoid using them where possible, the alternative is the Explicit wait, and these are a little more complicated and involve a little more work. This is because an Explicit wait will only wait as long as it needs too as opposed to waiting for a fixed period of time, but this requires some kind of logic behind it to deal with that. Whether that’s in the form of a while loop, some kind of recursive method or even the use of wait libraries built in to the likes of Selenium, there is very rarely a one line solution with Explicit waits. But the payoff from that extra work is huge, especially when done over a large number of tests.

Explicit waits can be written into utility helpers that can be used throughout your tests, this not only reduces the work required to be more efficient in your tests, it also makes for good code design in reducing code duplication and creating strong reusable methods.

As I said earlier though, don’t feel that you cannot use Implicit waits at all, sometimes you just can’t avoid it. And if you are in fact only waiting a maximum of a second, it probably makes sense to just use something like a Thread.Sleep. But then if you’re waiting on the same thing repeatedly for a second, then you should probably look at creating an Explicit wait method to deal with all those instances where it’s required.

And that’s what this is mostly about, using common sense and experience to determine which wait is right. Here are a few pointers you should think about when deciding.

  1. How often? If you’re waiting on the same element repeatedly at various points in your tests, ask yourself if it makes sense to keep using a set wait or whether it would be worth while creating a helper method to deal with it, and potentially reduce time over the course of its use.
  2. How long? If you’re waiting for more than a second, I’d argue that it’s always worth using an explicit wait. But also consider the variation of time the action can take, saving or loading animations can vary massively in time depending on system load, so you’d never want to set an Implicit wait, because you just have no idea how long it will take.
  3. Code Duplication? This combines both of the points above. If a wait takes an unknown amount of time but it’s only being used once in a single test, then is it really worth your time to write an elaborate helper method when on this single occasion, something in the test might be enough.

It’s easy when you’re getting used to writing tests, to overthink this and cause unnecessary stress. My advice to someone starting out would be to just write the test in a way that makes sense to you, use the advice I’ve given to help make a decision about what wait to use and when. But most importantly, if you get it wrong, you’re not stuck with it. Code refactoring is something you’ll be doing forever on your code, and that’s no bad thing. There is always room for improvement, and one day you might think of a brilliant way to deal with your unreliable page load times, and when you write that helper method to deal with it, suddenly you can improve your test to to use that method.

What matters is realising that if you use an Implicit wait, there is likely an alternative solution and you should address it when possible. But don’t bury your head in the sand and allow your tests to become time sinks.

So what are you waiting for?