We have test code like:


that's repeated in many places, where clickElement is called 1 to 5 times in a row. Should we make a helper function to consolidate these, e.g.:

clickElements([a, b, c]);

I've heard arguments against creating the helper function, that it makes it harder to read and that test code should be simpler. I've heard arguments for the helper function that it simplifies things and reduces code duplication. It seems like both camps are firmly convinced that their way is clearly better. Are there other important reasons for either that I'm missing or popular/standard resources on this?

  • Use your own judgement, remembering that people reading the test need to be able to understand what the test is all about - what the intent is, what the assumptions about the state of the system in that particular test are. So clickElements([a, b, c]) is fine - I understand what the idea is. Depending on the sytem, perhaps clickElementsSequentially([a, b, c]) is better, so that it isn't mistaken for some sort of a tripple-click combo gesture. On the other hand performTestActions() is bad because I have no idea what's happening or why - I need extra context to understand the test. Dec 2, 2020 at 21:40

3 Answers 3


Helper functions will certainly make code hard to read if you give them bad names.

Yes test code should be simple. But it can only be simple if you’ve written easily testable code. Helper functions won’t change that.

Helper functions can clutter the stack trace but with a good name they can make code easier to read. But simply eliminating duplicated code is not a good justification. Eliminate duplicated ideas that change together. Different ideas with identical code are fine without helpers. Test code is still code and it needs to be readable and flexible.

Anyone that says “no helper functions” all the time is wrong. Anyone that says “helper functions are fine” all the time is wrong. There simply isn’t a valid knee jerk reaction here.

Just because someone else successfully used a helper function doesn’t mean you should use it too. Even if everything works you might be folding together two different ideas that should be allowed to change independently.

If you keep that in mind before using helper functions I’m not likely to complain. It’s not a small thing. Think carefully. Remember many people will read it many times. Don’t waste their time just to save a little keyboard typing.


In general, I'd tend to not make the helper function except for in a particular scenario.

  1. Your tests are your first user. If your code is hard to use because it requires all of these repeated calls, then your real users are probably going to suffer from having to do all of those repeated operations. It's a smell, and the helper function just covers up the smell rather than fixing it.
  2. Tests should ideally fail for only one reason - the thing they're testing isn't working right. Helper functions provide a single point of failure, and a mistake there will cause widespread failure. They also usually end up in a shared library, that adds dependencies across tests that adds a build/maintenance cost.

That said, creating mocks tends to be a common, repetitive process and having a helper function to do all of the steps to setup a "good" mock service or a "no-op" mock service is pretty useful. It also provides a bit more value because when you change it, you'll want to change it for all of the tests that reference it. And it has less risk, since it's not the sort of process that users would normally go through.

  • @Telasytn It's UI test code that has to click a bunch of elements to go through a user workflow to test it. I'm not sure how that's a smell or how we could even eliminate it.
    – Josh
    Dec 2, 2020 at 21:09
  • @Josh - if your users have to click a bunch of elements to complete their workflow, they're maybe not going to like it...
    – Telastyn
    Dec 2, 2020 at 21:31
  • Unless you are testing navigation through the application. Or search results that allow for pagination or sorting. Clicking a lot in a UI test does not necessarily indicate bad design. It could just be a test case that requires lots of clicking to guard against race conditions or edge cases. Dec 3, 2020 at 0:46

I've found that automating the user interface to be a very finicky affair. Race conditions between the test runner and the application under test make for brittle tests that fail randomly for no apparent reason. Today you can click 3 elements in quick succession. Tomorrow somebody adds a fade-in effect that causes a race condition.

Be extremely weary of this reality. The bigger question is, how many places are you clicking those three specific elements? If anything about that interaction changes, you have a bunch of places to make that change, even if you user helper functions.

Instead, encapsulate that behavior in a Page Model. This gives you a proper layer of abstraction to insulate your tests from UI and navigation changes.

If you need to click three specific elements in 4 different tests, defining a Page Model method to perform these actions gives you the reusability that a helper offers, but also gives you a single place to refactor code should something about that interaction change.

  • It's not the same 3 elements. It's a helper function to sequentially click a list of different items, and it would call the existing function, that waits for the elements to appear.
    – Josh
    Dec 3, 2020 at 9:21
  • 1
    @Josh: Even so, my recommendation still stands. I've not found this type of helper function to be all that useful in UI automation code. Automating the user interface is fraught with complexity and multiple points of failure that are not immediately apparent. This is where I opt for writing more, but independent procedures, rather than trying to reduce and reuse code. That's just been my experience. Dec 3, 2020 at 13:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.