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?
Step MADNESS
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.
Step ambiguity
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
Simple architecture
- 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
Ruby compatibility
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!