Fast tests mean a fast feedback loop when doing TDD. Let’s make our tests fast with Guard.
A Jasmine spec in CoffeeScript:
describe 'A suite', ->
it 'contains spec with an expectation', ->
expect(true).toBe(true)
Gemfile:
source 'https://rubygems.org'
gem 'jasmine'
gem 'guard'
gem 'guard-coffeescript'
gem 'guard-livereload'
Guardfile:
guard :coffeescript, output: 'javascripts' do
watch(%r{^src/(.*)\.coffee})
end
guard :coffeescript, output: 'spec/javascripts' do
watch(%r{^spec/src/(.*)\.coffee})
end
guard 'livereload' do
watch(%r{^spec/javascripts/.*/(.*)\.js})
watch(%r{^spec/javascripts/(.*)\.js})
watch(%r{^javascripts/.*/(.*)\.js})
watch(%r{^javascripts/(.*)\.js})
end
This compiles CoffeeScript, watches our specs or Javascript files for changes, and reloads our browser automatically.
Start a jasmine server:
rake jasmine
Visit localhost:8888. See the results of the specs.
Change the specs or Javascript files and the browser will automatically reload.
The Four-Phase Test is a testing pattern, applicable to all programming languages and unit tests (not so much integration tests).
It takes the following general form:
test do
setup
exercise
verify
teardown
end
There are four distinct phases of the test. They are executed sequentially.
During setup, the system under test (usually a class, object, or method) is set up.
user = User.new(password: 'password')
During exercise, the system under test is executed.
user.save
During verification, the result of the exercise is verified against the developer’s expectations.
user.encrypted_password.should_not be_nil
During teardown, the system under test is reset to its pre-setup state.
This is usually handled implicitly by the language (releasing memory) or test framework (running inside a database transaction).
The four phases are wrapped into a named test to be referenced individually.
Our style guide advises we “Separate setup, exercise, verification, and teardown phases with newlines.”
it 'encrypts the password' do
user = User.new(password: 'password')
user.save
user.encrypted_password.should_not be_nil
end
Go forth and test in phases.
Written by Dan Croak.
Way back in mid-2007, when Rails 1.2 was the new hotness and GitHub was still a year away from crawling out of the primordial internet soup, prolific open source contributor Dr Nic wrote an article titled “8 steps for fixing other people’s code”. It offers excellent general advice, but the workflow details are clearly a product of their time: RubyForge, SVN, and .patch files feature heavily.
Here in the fantastical future world of 2012, while we still don’t have hoverboards or household nuclear fusion, we do have some great tools that make fixing other people’s code a lot easier. Join me as we rewrite “8 steps” for the modern age!
Open source projects are usually far from perfect. In many cases they started as something the author threw together to solve a problem, then released into the wild just in case it could be useful to someone else. Open source contributions come from regular people — just like you! — who start using the project and run into a bug that annoys them, or get an idea for a feature that would make their life easier.
The experience that prompted me to write this post started with finding a bug in Chronic, a date-parsing library. The issue is described in the pull request I submitted to fix it (pull requests are the final step in this process; we’ll get to them in a bit).
In recent years git and GitHub have emerged as the de facto standard, if not for open source projects in general, then at least for open source Ruby projects. Lucky you! In Dr Nic’s time it was all SVN, uphill both ways.
If your target project has a web site, it will probably link to the official GitHub repository. Failing that, you can search GitHub for the name of the project. This may also turn up other people’s forks of the project — if you’re not sure which one is the original, just pick one and follow the “forked from” links.
Once you’ve found the repository, scroll down to the README and scan it for “How to Contribute” directions. Some projects have a particular process they want contributors to follow, and it might be different from the steps outlined here. Chronic’s instructions are typical and straightforward.
Forking a project creates your own personal copy of the repository that you’re free to modify however you want. It’s integral to the GitHub workflow, and is therefore stupidly easy: Just hit the Fork button.

Copy the Read+Write link from your newly-forked repo and clone it down:
$ git clone git@github.com:grantovich/chronic.git
Cloning into 'chronic'...
Then copy the Read-Only link from the original repository (mojombo/chronic in my case) and add it as a “remote” like so:
$ cd chronic
$ git remote add upstream git://github.com/mojombo/chronic.git
Many projects use automated tests to ensure that bugs stay fixed and new features don’t introduce new bugs. Running a project’s tests is also a useful sanity check, since no tests should fail on an unmodified clone of the master branch.
Before doing this, you’ll need to install the project’s dependencies — if it has any, it should include a Gemfile. Use gem install bundler to install Bundler if you haven’t already, then simply bundle install.
In most Ruby projects, running “rake” with no arguments will execute the full test suite. Ensure this doesn’t give you any failures before proceeding.
Come up with a short, descriptive name for a branch that will contain your changes. Here’s my Chronic branch:
$ git checkout -b handle-sm-sd-with-time
Now you’re ready to start coding! Assuming the project has tests, you can do some TDD and start by writing a failing test. Poke around the existing test suite — it likely involves Minitest or Rspec — then write one or more new tests that would succeed if your feature existed or your bug was fixed.
Re-run the test suite to ensure your tests fail (and you didn’t somehow break any other tests). Then, write the code to make them pass! Follow the style of the existing code as much as possible, and resist the temptation to “clean up” or reformat things that aren’t relevant to your change.
Many libraries have Rake tasks applicable to this step. rake console is a common task that opens an IRB shell with your in-development copy of the library loaded into it. If the library is made available as a gem, there will be a task that builds the gem (e.g. rake build), and you’ll want to make sure this still works after you change things.
Note that while the changes I made to Chronic were in multiple commits, you should really put both the tests and the code that passes them into a single commit. Any given commit should pass all the tests that exist within it. You can still make multiple commits locally — just squash them later using git rebase -i origin/master.
If you’ve added a new feature or changed how something works, and the project’s documentation lives in the repository (this is usually true for at least the README file), update it to be consistent with your changes. Documentation never gets enough love, and the owner will probably appreciate your thoughtfulness.
Pull down any changes made to the original repository since you started working, and replay your commits onto the updated code. This ensures that your changes can still be successfully applied to the latest version. It sounds complicated, but the commands are quite simple:
$ git fetch upstream
$ git rebase upstream/master
Here’s the other half of the fork-based GitHub workflow. After making changes in your fork, you request that the original author pull those changes into their repository.
First push the branch containing your commits up to GitHub…
$ git push -u
…then hit the Pull Request button on your forked repository.

Set the “head branch” on the right side of the pull request to your new branch.

You’ll be prompted to give your pull request a title (e.g. “Add support for XYZ”) and detailed description. Fill these in, and hit the Send pull request button!
Now comes the hardest part: Waiting. The owners of the repository will be notified of your pull request, and at some point — hopefully — will get around to reviewing it. They might suggest some changes: Make them in your branch and git push, and the pull request will automatically update with your new commits. If your changes look good, they’ll be officially merged into the project. Success!
After you’ve done this once for a given project, the process is simplified: When you’re ready to contribute again, git pull upstream master so you’re working with the latest code, and start again from step 4.
While the GitHub web interface is more accessible if you’re not used to the workflow yet, it’s actually possible to do all this without leaving your terminal. Check out the hub tool, and more specifically the commands dealing with forks and pull requests. In fact, my Chronic pull request was originally a bug report that I later “converted” using hub.
Remember these steps are more like guidelines than actual rules. Every project is different, and the owners of the one you’re working on might prefer you do things a bit (or a lot) differently. Be receptive to the feedback you get on your pull requests, even if it seems nitpicky. You’ll be hailed as a model open source citizen in no time!
Have you ever added a seemingly innocent validation to a model, like so:
class User < ActiveRecord::Base
validates_presence_of :first_name
end
And then had this happen?:
$ rake spec

If you’re using FactoryGirl, this can often happen because you haven’t updated your factory to respect the new validation.
Of course, the fix is simple:
# spec/factories.rb
FactoryGirl.define do
factory :user do
first_name 'Jonah'
end
end
But how do you save yourself the time (and potential heart attack) of watching all those dreaded Fs go by?
My old solution used to be adding a boilerplate test in each model’s unit spec, like so:
# spec/models/user_spec.rb
describe User do
it 'has a valid Factory' do
build(:user).should be_valid
end
end
This is better than nothing, but it has two major problems.
Enter our savior, the factories_spec.rb:
# spec/factories_spec.rb
FactoryGirl.factories.map(&:name).each do |factory_name|
describe "The #{factory_name} factory" do
it 'is valid' do
build(factory_name).should be_valid
end
end
end
Fancytime! Now all our factory specs are in one place, DRY as a desert.
On to the second problem: we don’t want to wait for all our specs to run to deal with this error.
If you use rake to run your tests, one way to take care of this is by adding a pre-requisite to your rake spec task:
# Rakefile
desc 'Run factory specs.'
RSpec::Core::RakeTask.new(:factory_specs) do |t|
t.pattern = './spec/factories_spec.rb'
end
task spec: :factory_specs
Now the :factory_specs task will need to run and succeed before the whole suite is run. If you have a bad factory, you’ll know right away with a nice failure message:
$ rake spec

No more panic attacks necessary.

Just one of the many new things I’ve learned in my first day as a thoughtbot apprentice!
Draper is a handy new gem for extracting logic normally held in helpers and views into something Ruby developers love: objects! Helpers are a great means to an end, but most of the time, our helpers accept arguments, a great sign that the method is procedural instead of being a method on the object we’re passing.
In my Intro to Test-Driven Rails workshop (which I’m holding September 17-18 in San Francisco and September 24-25 in Boston), one of the apps we build is a simple todo tracker. I decided to try out Draper in the codebase and see how things turned out; let’s dig in to some code and see what it can do!
Here’s the helper in question:
# app/helpers/todos_helper.rb
module TodosHelper
def completion_link(todo)
if todo.completed_at?
link_to 'Incomplete', todo_completion_path(todo), method: :delete
else
link_to 'Complete', todo_completion_path(todo), method: :post
end
end
def todo_state(todo)
if todo.completed_at
'complete'
else
''
end
end
end
Fairly straightforward: we have completion_link, which either POSTs or
DELETEs to /todos/:id/completion (adding or removing the timestamp of
completed_at), and todo_state, which generates an HTML class for us.
The view shouldn’t be much of a surprise:
<%= link_to 'Create a Todo', new_todo_path %>
<ul id='my-todos'>
<% @todos.each do |todo| %>
<li class='<%= todo_state todo %>' id='<%= dom_id todo %>'>
<%= todo.description %>
<%= completion_link todo %>
</li>
<% end %>
</ul>
As I mentioned above, helper methods that accept some instance of a model are
begging to be moved to an object that can instead be instantiated with that
model; in this case, a TodoDecorator.
My ideal interface would look like:
<%= todo.list_item do %>
<%= todo.description %>
<%= todo.completion_link %>
<% end %>
This provides the flexibility of adding whatever markup within the <li>
while moving the logic for id/class generation (as well as the
complete/incomplete links) out of the helper. Now that I know the interface,
let’s write some tests.
First, require the correct file in the RSpec helper:
require 'draper/test/rspec_integration'
To generate the decorator and its test, run:
rails generate decorator Todo
With that added, let’s test-drive the implementation. First, the list_item
method:
# spec/decorators/todo_decorator_spec.rb
describe TodoDecorator do
context 'list_item' do
it 'renders list item for complete todo' do
todo = build_stubbed(:todo, :completed)
result = TodoDecorator.new(todo).list_item do
'string'
end
markup = Capybara.string(result)
markup.should have_css("li#todo_#{todo.id}.complete",
text: 'string')
end
it 'renders list item for incomplete todo' do
todo = build_stubbed(:todo)
result = TodoDecorator.new(todo).list_item do
'string'
end
markup = Capybara.string(result)
markup.should have_css("li#todo_#{todo.id}:not(.complete)",
text: 'string')
end
end
end
I test both complete and incomplete todos, ensuring that the text within the
block is present. Capybara.string makes it really easy to write assertions
against the generated markup.
Next, let’s test completion_link:
describe TodoDecorator do
include Rails.application.routes.url_helpers
context 'completion_link' do
it 'generates a link to complete the todo when incomplete' do
todo = build_stubbed(:todo)
result = TodoDecorator.new(todo).completion_link
markup = Capybara.string(result)
markup.should have_css("a[data-method='post'][href='#{todo_completion_path(todo)}']",
text: 'Complete')
end
it 'generates a link to mark the todo as incomplete when complete' do
todo = build_stubbed(:todo, :completed)
result = TodoDecorator.new(todo).completion_link
markup = Capybara.string(result)
markup.should have_css("a[data-method='delete'][href='#{todo_completion_path(todo)}']",
text: 'Incomplete')
end
end
# context 'list_item' ...
end
Finally, the decorator implementation:
class TodoDecorator < Draper::Base
decorates :todo
def list_item(&block)
h.content_tag(:li, list_item_options, &block)
end
def completion_link
if completed_at?
h.link_to 'Incomplete', completion_path, method: :delete
else
h.link_to 'Complete', completion_path, method: :post
end
end
private
def completion_path
h.todo_completion_path(self)
end
def dom_id
h.dom_id(self)
end
def list_item_options
{ id: dom_id, class: state }
end
def state
if completed_at?
'complete'
end
end
end
This should look familiar since the majority of it came from the existing
helper. The biggest thing to note is accessing helper methods versus methods
on the decorated component. Helper methods are accessed by calling them on
h, which represents Rails’ helpers; this includes routes, record identifiers
(like dom_id), and tag generators (link_to, content_tag). Methods on
the decorated component (todo) can be invoked directly. Finally, if you don’t
want to prefix helper methods with h., just include Draper::LazyHelpers in
your decorator.
The view can now be changed to my desired implementation, and the suite is still green! What are the benefits to a decorator versus leaving logic in the view and helpers?
I’ve only recently started playing with the draper gem but I really enjoy it. The benefits are pretty clear to me and I love the fact that it’s so easily testable. If you’ve got procedural code or logic in your views (or methods on your models that are purely view-specific) I’d recommend moving those methods to a better place: a decorator.