Writing behavior driven development tests with the Gherkin syntax is a great way for a developer to communicate with a non-technical employee, for example a product manager. This is because the Gherkin syntax is so close to English, that it doesn’t require any technical expertise to read or write it. It just has to be written in a consistent and known way, so that it can be interpreted into steps of executable code.
Many languages have great BDD Gherkin libraries, like Cucumber for Ruby and Behat for PHP. The one that I think is best right now for the Elixir language is the White Bread library created by meadsteve.
This article isn’t a getting started guide on White Bread, if you’re looking for that I’d recommend taking a look at the README.md
of the White Bread project. This article is instead more of a tips and tricks guide to getting the best from White Bread (and Gherkin in general) based on my experiences.
The first recommendation is one that can be applied to writing Gherkin for any programming language. That is, to write your Gherkin steps in a reusable and explicit way. First, I’ll show you an example of what not to do, then explain how we can clean up the mess. Let’s start off with a feature file that looks like this:
Now, each of these steps is written similarly but have slight differences and therefore require different implementations in the code. Let’s look at the context code that matches up with these steps:
I’ve omitted some of the steps from the context above, but you can already see how much repetition there is between similar steps. In order to get around this, the steps should be written in a reusable way, in which variables can be used, so that the same context step can be executed for each one, as shown below:
This allows the same steps to be used, even when the names used for the user name varies, as we can see:
The steps above are using the power of Regex to capture the name between the two speech marks and set that as the name
variable.
We can take the cleanup of this feature file even further. What if we wanted to write a step to change the email address of a user? That’s so close to changing the name, why use two different steps?
This would allow the same step to be used, regardless of which property of a user is being changed.
What if I wanted to register a user, but didn’t care about giving them a specific name. I could come up with a default name (e.g. John) and then refactor the steps like so:
The idea behind this refactoring is so that you can write as little code as possible and that you keep your code DRY (Don’t Repeat Yourself). But you can end up taking the refactoring too far and push the Gherkin syntax to a point where a non-technical person would not be able to understand it clearly, so keep that in mind when doing this sort of refactoring.
The second thing I’d recommend is that each feature file has its own context file. The way that I have set this up is to also have one suite per feature file, there is a context_per_feature
configuration, but I found this cumbersome to use. So, my config file would look something like this:
The reason I have done this is so that each feature can have its own entry point into all the different context modules you will be writing.
The third thing I’d recommend is that when you find yourself writing a step that can be reused for multiple features, put it in its own context! That way each feature can share this common step.
One step I often find myself needing is a step where nothing happens. This may sound silly at first, but the Gherkin languages requires that each feature has a Given, When and Then step and sometimes I don’t need any setup in the Given step. It looks like this:
In order to add this to another context I’d use subcontext
which looks like this:
This way my contexts that are the entry points from the feature files remain small and will only have steps in them specific to the feature, it also helps keep the code DRY.
One final recommendation is to create a module with state helper functions.
White Bread allows you to pass on state between each step, which is required if, for example, in the first step you add a user and get their ID and then in the next step need that ID to make further modifications on the user.
The state is just a map, so adding data to it is easy, but its nice to encapsulate that logic in some helper functions, like this:
Using these helper functions, our example from earlier would now look like this:
The benefit of doing this may not be apparent yet, but once you have 20+ context files all manipulating the state in possibly slightly different ways, the benefit will become apparent.
That’s it! Thanks for reading and I hope you found some of the tips and tricks above useful.
As a final word, I’d implore you to contribute to the White Bread project. Elixir is a language growing bigger every day and it needs a strong BDD Gherkin library and I think White Bread can become that.
Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising &sponsorship opportunities.
To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.
If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!