Seamless automation of processes that involve more than one platform can present problems in Cucumber script readability and maintenance. The scenarios can become complex and much too code-like for understanding from the business perspective. Maintenance of existing scripts and creation of new scripts can become problematic because the ‘language’ represented by the step definition files becomes inconsistent and too complex.
Consider an enterprise event planning and management application. It encompasses two applications: a centralized, desktop browser based application used to create and oversee the events, and a mobile app that event attendees use to get information (schedules, maps, presenters, sponsors, and etc.) to help them navigate the event. All of the mobile functionality is also available on the desktop application.
Let’s take the example of a notification, or alert, that needs to be sent to all attendees of an event to let them know of a time change for one of the sessions. The event manager creates the alert and sends it to all event attendees. Each attendee receives the message on the mobile app. If an attendee opens the alert and has the choice to respond to it or not. The response is returned to the main application and reported.
Here is what this might look like in a Cucumber feature file:
The problem here is that it is not obvious when the mobile or the desktop application is being exercised. There are clues (‘I log on to the mobile app’, ‘I log out of the desktop application’) but they often don’t appear where the change of platform happens. The large number of steps make the high level use case (send alert, acknowledge alert, confirm acknowledgement) very hard to discern.
The ‘Background:’ section covers starting both the mobile and the desktop pieces. The first step (line 5) is a reminder to the tester. The mobile device has to be turned on, connected, the app loaded and started. These often include manual tasks and, while they have to be performed, there are usually quite a few tasks and the details should not clutter up the Feature file.
The second step (line 6) calls a step definition that starts the browser, logs in to the desktop app as a default user and navigates to the specified page. One difficulty here is that, in Cucumber, the Background: section is repeated for every Scenario in the Feature. It isn’t clear in subsequent Scenarios which platform the process starts in, or obvious where the platform changes within a single Scenario.
Once both platforms are up and connected, switching between them is a matter of the step definitions knowing which application to talk to. There are a number of ways to handle this in the step definitions called from the feature file.
We’ll look at two:
2. A method called at the beginning of each step definition to determine the platform and let all step definitions know the current platform:
Either will work; However, 2 is preferable because it requires fewer step definitions and a lot less code. It helps keep the step definitions DRY (“Don’t Repeat Yourself”). The code in the which_platform?() could easily be inside the step definition that calls it, but that makes the step definition more confusing to the non-developer who is trying to understand the business flow and interpret test results. More importantly, it makes the Scenario more clear and looking less like code.
Notice also that empty lines have been added at the beginning of each set of steps against a different platform. This makes the change in focus more visible. Step definitions that don’t need to be different between the platforms automatically point to the current one. Those that do have differences between platforms can query the type of the current platform and execute the correct code to perform the action or actions called for by the step.
The step ‘I log in as “[role]”’ might look something like this:
The complexity of variations in log on code between the platforms is hidden in Ruby methods. Notice that the login credentials are obtained for the role by another Ruby method. This separates how and where they are stored from the step definition, keeping it as simple as possible.
The Bottom Line
- Keep the step definitions DRY.
- Try not to do separate step definitions for every variation of the same function or action.
- Abstract business actions into shorter step definitions.
- Think ‘what’, not ‘how’.
- Remember the intended audiences for the Feature file and step definitions.
- Move details deeper as much as possible.
- Factor actual ‘code’ into Ruby methods or nested step definitions.
These will help any Cucumber testing to be more readable, usable, and maintainable. It doesn’t matter if the tests involve switching between platforms. Take the time to understand the use case that is being tested and make that as clear as possible in the Feature file and Scenarios.
A Caveat: Cucumber loads all the files under the step definitions into a single name space. This means that step definitions and methods in all step definition files must be uniquely named. If you have separate files for each platform which have a step “Then /I navigate to the “([^”]*)” page/ do…”, you will only be able to use the last one loaded by Cucumber.