How to achieve more clean, encapsulated, modular step definitions with Spinach
Spinach is a new awesome BDD framework that features encapsulation and modularity of your step definitions.
We've been using Cucumber for a while now, and we must say we fell in love with it from the first moment.
But not anymore: It broke our hearts.
You know, we realized what we really loved about Cucumber wasn't Cucumber itself but Gherkin. Gherkin is the feature parser behind it and has some really nice features:
- A really natural DSL (as natural as it can be)
- A simple way to abstract a feature description
- It helps you focus on business value , even if there's no real impact on the actual execution (In order to...)
But what sucks about cucumber?
Where exactly should I put my step definitions? What if they're corelated - can I abstract them in a simple way? Can I reuse them across projects? Could I even test them?
With cucumber, you usually run into this kind of situations and there's no easy way to get over it. You should use better step file namings perhaps? Create some methods that live next to each other in the cucumber World? Nah, it just doesn't feel good.
Sharing steps between all the features in your project just doesn't scale. It's fine if you have a couple of features, but you start hitting ambiguous steps when it grows off a certain limit.
And when that happens, you must write them taking in account the ones written before, and just having your mind somewhere else misses the whole point of writing them - you should focus on your feature
Regexp-based step matching
Reusable Cucumber steps == ugly steps. If you want a to reuse the same step between multiple situations, either you're going too far in the integration tests (and thus you should be doing that in the unit tests) or you should be writing some helper methods.
It just doesn't feel good not to have explicitly defined what step is being executed. It's like metaprogramming: it can be useful, but most of the times is a bad habit.
So, for that... we made Spinach
Spinach focuses on step reusability and encapsulation so you can reuse them in a clean way across features and projects.
- Features are just Ruby classes
- Leverages Gherkin parser
- Steps are just Ruby methods
- Supports MiniTest and RSpec as well as Capybara
Fighting step madness and ambiguity
- Each feature has its own steps (so no more global steps)
- Explicit reusability through Ruby mixins
- Small codebase
- Fully documented
- Simple hooks system
Show me an example
Given this feature
Feature: Test how spinach works In order to know what the heck is spinach As a developer I want it to behave in an expected way Scenario: Formal greeting Given I have an empty array And I append my first name and my last name to it When I pass it to my super-duper method Then the output should contain a formal greeting Scenario: Informal greeting Given I have an empty array And I append only my first name to it When I pass it to my super-duper method Then the output should contain a casual greeting
This is how its Spinach feature steps file looks
class TestHowSpinachWorks < Spinach::FeatureSteps Given 'I have an empty array' do @array = Array.new end And 'I append my first name and my last name to it' do @array += ["John", "Doe"] end When 'I pass it to my super-duper method' do @output = capture_output do Greeter.greet(@array) end end Then 'the output should contain a formal salutation' do @output.must_include "Hello, mr. John Doe" end And 'I append only my first name to it' do @array += ["John"] end Then 'the output should contain a casual salutation' do @output.must_include "Yo, John! Whassup?" end private def capture_output out = StreamIO.new $stdout = out $stderr = out yield $stdout = STDOUT $stderr = STDERR out.string end end
Spinach runs on MRI 1.9 and Rubinius/JRuby support is on the works.
Note that not giving support for MRI 1.8.7 is a purposeful choice and not a negligence. This is new software, why should we encourage using legacy versions?
So if you wanna give it a try, here's all you need:
We would really love some feedback. Hope you like it!