Jan 10 • Artem Bondar

Cucumber - not a test automation tool

Cucumber - is one of the most well-known tools in the world of test automation. What is not so well-known - is how misused this tool is. Let me try to explain and demonstrate why in 99% of the cases, test automation projects do not need Cucumber. There is a better way.
If you don't believe me, will you believe the person who actually created Cucumber? In 2013, Aslak Hellesoy, the creator of the Cucumber tool, wrote a blog post "The world's most misunderstood collaboration tool". It begins with a phrase: "If you think Cucumber is a testing tool, please read on, because you are wrong". It's like a scream to a community, frustration, that software development teams don't understand how Cucumber actually should be used. I highly recommend reading it first, to get your feet wet on this topic. In 2020 he made another blog post, related to the current topic "BDD is not test automation". Read it as well, just to understand that activities that are often called as a BDD are not actually a BDD. Writing features and scenarios for test automation scripts - is not BDD. BDD is an entirely different process, that requires close collaboration of the whole team. QA does not perform any automation, the developer does, because they do the development, Behavior-Driven Development. Documented and automated behavior - drives the development. Outside-In. Not the other way around.

Breaking Myths

I would like to keep the focus on test automation, so want to begin by breaking some myths about how automation engineers explain the decision of using the Cucumber.
Myth No.1: "We use Cucumber so non-technical people (POs, BAs) can read test scenarios and execute them". 

Well... let's be honest. POs and BAs don't really need to look at the Scenario that covers some automation flow. If they need, they will ask you like "Hey John, which of the scenarios that were demoed last sprint are automated? Can you show it?" PO will not spend his time trying to find the right feature file to read it. Especially trying to execute it. How often did you see PO that runs the "git clone" command? There is always can be an exception, sometimes PO can be super technical or maybe he/she was QA in the past. Or, the company was able really to adopt BDD! But in most cases, POs and BAs care about the project/sprint backlog planning, timelines of the project, and making sure stakeholders are satisfied. They don't care about whether the team has automation tests or not. They need the project to be completed, on time, bugs free. Will it be done with automation or not - does not matter for them.

By the way, you can write "human-readable" test scripts without Cucumber so PO, if they really want, can read it. I'll show it later, how.
Myth No.2: "We use Cucumber, so non-technical QAs can write automated tests reusing already created step definitions"

This is possible but supper inefficient. Let me explain. Each test step in the Cucumber scenario will require creating a step definition, that holds the actual code implementation. The number of lines of code for a single step depends on the scope of the step. If the step says just "Click Submit button", then it's just one line of code in the implementation. But if the step says something like "User fill out the New Customer form", then the implementation will be bigger, to fill out all fields in the form. Those step definitions were created by automation engineers, hoping that non-technical QA can reuse is when he/she needs to fill out the form or click submit in the automated scenario. Now imagine the functionality of the application slightly changed, and the "New Customer form" has an optional checkbox. Non-technical QA can't use the existing step definition, because it's not doing what he needs. He goes to the automation engineer, asking to create a new step definition or update the existing one to handle the checkbox. Then PR. Then merge. Then "git pull" by non-technical QA and he can move forward. And this process repeats again and again, every single time when non-technical QA can't continue the flow. How about if the test failed, for example, an element not found? Non-technical QA can't tell why it failed and how to fix it. Again, he/she will go to an automation engineer who can debug, fix and create PR. 

Writing the test scripts that way becomes super slow and inefficient. It's only visibility, that non-technical QAs contribute to automation. It can be proudly shown in beautiful presentations to management. But in reality, it just does not really work and can be done better.
Myth No.3: "We use Cucumber as a level of abstraction for test implementation, so we can re-use step definitions and not copy/paste the code between tests"

Partially true with limitations. If you want to create an abstraction, i.e. wrap the code into a reusable component, Cucumber is not needed for it! Every programming language can do it :) Create whatever needed abstraction layers in the code and reuse it the same way! If you work in VS Code then using Cucumber becomes difficult, because the Cucumber extension is not perfect and many people often have issues with IntelliSense and code complete support. When you want to jump from the feature file into the implementation of the step with Cmd+Click (on Mac) or Ctrl+Click (on Windows), sometimes it does not work. So need to manually search for the step name in the step definition file to find a particular implementation. When you have many of those steps, it's easy to get lost which inevitably results in the creation of duplicated steps with slightly different names, same or similar implementation.
If all you are looking for is a way to organize the test code - use the power of the programming language that you are working with. Cucumber is not needed and is harmful in this case.
So what do we have so far?

If your company does not have a vertically integrated Behavior Driven Development process of software development and Cucumber's scope in the framework is only for writing "human-readable" scenarios for test automation after the feature is implemented - Cucumber is simply not needed. You, as an automation engineer, can do it better, faster, and more efficiently by choosing a different approach.


The answer is - page objects!

True Page Objects

Page Objects - the most popular concept in test automation world. But not all page objects are the same. There is no single standard, "best practice" that would be agreed and adopted by community. Everyone has own vision and implementation. I have my own. I think the only agreement in the community is general definition of page objects, something like: "Every page of application has it's own class/file, and this class/file has methods responsible for operations on that page". Sounds straightforward, but the number of possible implementations of this concept is endless. Every project I saw has own "flavor" of page objects.

Here are the fundamental concepts of my approach:

  • Naming! The most important part. The names for the methods have to be well descriptive. No double meaning. After reading the method name you need to understand exactly what is it doing. Good naming is actually harder than you think!
cypress method with bad name clkBtn() with a single line of code
  • Slice by logic, not by pages when needed. While "class per page" approach mostly works well, it should not be a hard rule. If a certain big reusable component is used across different physical pages - create a new class for it. Sometimes entire framework architecture is sliced by logic groups only.
  • Avoid multiple layers of abstraction. Try not to use more than 3 layers. Keep the architecture as simple as possible. First layer - tests. Second layer - implementation methods. Third layer - complimentary reusable helper methods for the second layer.
  • Avoid tiny methods. Putting a single line of code in method increase the level of noise, maintenance efforts and complexity. Instead of reducing the number of lines of code in the project, you add more out of "thin air". Try to avoid as much as possible. It does not mean that it's no no. Just avoid.
one line cypress method to click on the button
  • Develop a naming convention for the project and follow it! It's important to implement, so you or any other engineer will be able to quickly navigate across the project to find reusable components. For example: for all buttons naming is "click"+"textOnButton"+"Button". CamelCase. Or for all forms "fill"+"nameOfTheForm"+"Form". And so on.
  • Parametrize methods as much as possible. This way you increase the flexibility of how method can be re-used and reduce the number of lines of code in the project.
  • Keep locators inside of the methods. Many of you will disagree saying that locators will be duplicated in this case. But if you follow P.4 (avoid tiny methods) - they will not. This simplify the maintenance efforts by a lot and significantly reduce number of lines of code. I can proof the true of this statement but will require a separate article.
  • And the last one. Make sure methods holds as much logic as possible! Following P.4 and P.7, design methods in a way to be responsible for "sections" of application logic and user flow. This also simplifies framework maintenance down the road. For example, if you need to fill the login form with username, password and click submit, don't create 3 methods, one to fill username, one for password and one for clicking the button. Create one method that is responsible for login operation.
Overall, don't overcomplicate simple things. Don't try to impress your developers by introducing some fancy design patterns in the automation framework. Better try to impress the team with the stability of the tests, speed of execution, and fast feedback loop that is capable of catching defects. Complex and flaky automation that the development team doesn't trust - is useless.

Replacing Cucumber with Page Objects

Now when I shared my recommended concepts for page objects, let's see how it can be used instead of Cucumber.

Imagine you have a login page that you planning to automate, for example, this:
a form with username, password and sign in button
You create a Cucumber feature file and new Scenario for it, that would look something like this:
Cucumber code example
This is how the same scenario can be written with page objects in Cypress:
alternative example written with page objects
Is it readable? Yes! Are POs and BAs can read and understand this scenario if they need? Yes! Are non-technical QAs, if you really want them, able to use these understandable methods to write tests? Also Yes!

Even if this "readability" is not enough, you can always add human readable comments right into the code. No problem at all!
readable code with page objects
Even more. Using the power of IDE, you can add annotations to test methods, providing additional descriptions what this method is doing and which parameters to use, like this:
methods annotation
Then in the test, if you hover over the mouse above the method name, you will see a pop up window with a description how to use this method properly:
intellicence example with annotation
And the last thing is navigation in the code base. When you logically slice your application in page object classes, then you can easily navigate between those objects with "dot notation" and code complete, to quickly check which methods are already available and can be re-used. Much more comfortable than searching for step definitions.
demonstation of dot notation to read page objects
As you can see, Page Objects give you more flexibility, convenience and pretty much the same readability of the tests. If company don't use true BDD, Cucumber for just test automation is not needed.

Transition to BDD

Let's say you decided to build framework using only page objects. One year later, company decided to make pivot to adopt true BDD, when team write scenarios first, write automation code and only after that develop application code. Great! With a page objects, it will be very easy transition. Everything you ll need is to call already existing page object methods from step definition implementation. Easy! If your team really decide to go BDD route, make sure Scenarios are written how they suppose to be. The example of Scenario I showed before is fundamentally incorrect, but unfortunately this is how automation engineers use Cucumber. Read a quick blog post from Aslak with a good example: "Are you doing BDD? Or are you just using Cucumber?"

Final thoughts

I hope this content was convincing enough to re-think your approach to test automation. Page Objects is not a magic pill, but it's a powerful technique to organize and manage the test code efficiently. In test automation, focus on what is the most important: speed, reliability, relevance of the tests! You are an engineer, so activate your critical thinking to engineer tests most efficiently! Study best practices and don't be afraid to experiment. Study best practices and don't be afraid to experiment.
I wish you to build the frameworks in a way that the person who comes to the project after you will not say: "we need to start from scratch" :)
Microsoft Playwright growing in popularity on the market very quickly and soon will be a mainstream framework and replace Selenium over time.
Get the new skills at Bondar Academy with SDET with Playwright course. Start from scratch and become an expert to increase your value on the market!