I quite frequently come across a scenario that looks something like this:
Scenario: Create some animals Given I am a zoo keeper When I create a giraffe And I create a lion And I create a pony And I create a unicorn Then I should have a zoo
and step definitions that implement the When steps with a single step definition:
When /^I create a (\D+)$/ do |animal| case animal when 'lion' create_a_lion() when 'giraffe' create_a_giraffe() when 'pony' create_a_pony() else raise 'Unknown animal' end end
I don’t like having case statements in steps for a number of reasons:
- For readability and maintainability reasons I try to keep my step definitions as short as possible (usually a couple of lines), and using a case statement violates this principle;
- Raising an exception to catch invalid usage of the step (in an else clause) replicates what these BDD frameworks already do, provide feedback about unimplemented steps;
- IDEs that support step auto completion (such as RubyMine & Visual Studio) will not suggest valid steps as they don’t understand how you’ve implemented a case statement; and
- If used inappropriately (such as our unicorn step), the test will only fail at run-time whereas most IDEs will highlight non-matching steps as you’re writing.
For example, you could change our steps to look something like this:
When /^I create a lion$/ do create_a_lion() end When /^I create a giraffe$/ do create_a_giraffe() end When /^I create a pony/ do create_a_pony() end
Even though this is three times as many step definitions, it is actually less code (9 lines compared to 12).
By using this approach it is obvious we can’t currently create a unicorn as RubyMine tells us before we even run our tests. And we don’t need to raise any exceptions myself.
Whilst a lot of people use case statements in steps to reduce the number of steps, it is actually counter intuitive as it means you have more code to do so, and the outcome is less usable when writing scenarios. So, please avoid putting case statements in your step definitions.