Behavioral Driven Design with Cucumber
Testing with Cucumber, Sinatra and Capybara
(originally published on my blog on June 2013)
Everything you need to know
There are many elements you need to simultaneously learn to do effective testing of your code. Because some of these elements are very simple a lot of explanations just jump over what you need to know and give them up as obvious. Let’s start with a list of the things you need to learn:
- Gherkin (the language of Cucumber)
- Capybara (the DSL that controls the browser tests)
- Rspec (the DSL in which the actual pass/fail tests are written.)
None of these are hard. But having to learn all at the same time can seem daunting. But it’s not! It’s easy peasy but takes time.
It took me three days to get a handle on this. And I hope by reading this you’ll get a handle on it much much quicker.
Let’s start with Cucumber first.
Cucumber
Five things you need to know about Cucumber:
- Cucumber tests are located on a folder that have plain text files with a extension and written in Gherkin.
- The files contain tests that have a (1.) heading that explains what feature of the program you’re testing, with a (2.) tag that follows it and the Scenario uses keywords (3. ) to define the steps you go through testing your scenario. These keywords aren’t important (they can all be substituted by anything) they just refer to how they’re defined.
- Because when you run your features files with the output will give you exactly what you need to put on your step definition file to actually create the tests.
- The feature files refer to files in the directory. These are plain ruby files that have the same name as the feature files but with at the end instead of extension. This is where you can paste the output of the previous command.
- The configuration file is in the folder and called . This is automatically generated by cucumber-sinatra below.
That’s pretty much it for Cucumber. The step definitions have regex that matches the steps and a block that runs some code that actually creates the test but that’s all Ruby.
Side Note: You can use escaped (w/ a backslash) Markdown inside your Gherkin (feature files).
Example:
Cucumber-Sinatra
What does is set all the config files for your Sinatra Application to run cucumber with capybara and rspec and creates a sample step file with common step definitions such as . These are placed in the file called in the directory inside the directory.
In order for this to work needs to know the class name of your modular Sinatra App and the path to the ruby file where it’s located.
To generate these files you do:
Capybara
Capybara is a DSL for interacting with a web application. It’s the successor of a previous tool called ‘WebRat’ (hence the name, a capybara is a large cute rodent).
Capybara allows you to run your Sinatra application in two ways:
- Fast one directly through Rack (which doesn’t run the javascript on your page).
- Slower one through a headless browser using Selenium by default.
To run the second one all you need to do is preface your scenario with a tag.
Example:
Almost all the steps above are already generated by cucumber-rails. I use the @javascript tag because the language switching is done by javascript on the page. The only step I had to define was “Then The page redraws in English” & “And the html lang attribute is not ‘es’”. Since the first one of those is mainly rspec I’ll discuss that one later.
This step is defined in Ruby with a regex (regular expression) that feeds whatever is within the ” ” quotes to a block as a variable I called . Then I call on a Capybara Query () to check that hat the html language attribute is not set to the variable supplied in quotes.
Capybara provides a rich DSL for interacting with the page elements. I found an excellent cheat sheet here. It’s pretty straight forward and relies on many of the same CSS matching elements as JQuery does. But most tests will require more than just a quick check of something with Capybara, Capybara typically just gets you the elements you need to test, and you test those expectations withrspec.
Side Note: To explore Capybara inside pry (or irb) just and then and you should have access to all the Capybara objects. (try in pry.)
Rspec
Rspec is another DSL for writing tests. Not just cucumber tests but any kind of test from unit to acceptance. Rspec looks super complicated to me, but that’s mostly because the old syntax (should) tries to be so much like a natural English sentence that it becomes harder to understand. I much prefer the new (expect) syntax. So lets look at an example.
Example:
This example sets a variable to the path using Capybara’s current_url method. Then creates an expectation of what part of that path should be. I find this new syntax much easier to read since the methods are clearly called. Here is a blog post by one of the Rspec maintainers describing the new syntax.
So, what is this testing exactly, anyway? The way the language feature works on the webpage it uses javascript to change the path appending the language tag to the beginning of the page.
Rspec has mocks (fake objects) and other goodies. But to get started all you need is the simple ‘’ syntax. Most cheat sheets include only the old syntax, here is one for the new one. Please note that and are aliases and you can use whichever you like (I prefer the later).
Side Note: To load Rspec on pry (or irb) just and .
BDD, Testing and why do testing?
A key element to Behavior-Driven-Development (BDD), that I recently understood, is that the highest-level tests (the so called acceptance tests), the ones that are done in cucumber, are the ones that provide the most value. I’d seen presentations of BDD and TDD (test-driven-development) and many seemed only useful for expert programmers that knew how to solve the problem. But truly the best value tests give you are: documentation, introspection, and coverage for refactoring.
Yet only the third one requires some extensive testing. The first two can be satisfied to some extent solely with cucumber tests. By just looking at the test you know that the language switching occurs in javascript and does something to the path, specifically to the first element of the path. This is valuable knowledge for developers and maintainers looking at your application code.
The second one, introspection, forces you to think about code that is testable, maintainable and can grow. So even a happy-path test that just test what the application is supposed to do, can be very useful. By writing tests after the application was working, I was able to locate bugs that I had missed simply because the test required me to think in a different way and look at the code form a different perspective. For more on BDD you can look at this youtube video.
Testing Middleware
This setup above works very well for Sinatra based apps, but not for Rack Middleware. I’m still figuring how to effectively do cucumber tests for that.
Update: I figure out how to do it. Open the file and change this line to this long as thing below.
Capybara.app = eval "Rack::Builder.new {( " + File.read(File.dirname(__FILE__) +
'/../../config.ru') + "\n )}"
— David