new controller examples
June 30th, 2008
There’s been a lot of discussion about clarity over DRY lately. This is something that I’ve been espousing for some time, but recent posts by Jay Fields, Mikel Lindsaar and Dan North have gotten me thinking about it again with more focus.
With this in mind, I’ve been refining the examples generated for restful controllers when you run script/generate rspec_scaffold with the rspec-rails plugin. I’ve got them now where I’m pretty happy with them, but I’m curious to hear what you think. I’m not going to tell you what I changed or what to look for, I’m just going to ask you to look it over and post your comments.
There are two listings: the generated code and the output you get from running the examples. Thanks in advance for any feedback.
Read the rest of this entryPresenting at RailsConf 2008
January 26th, 2008
I’m going to be presenting at RailsConf 2008 on RSpec’s Story Runner. I’ll be talking about how I approach writing for the Story Runner and address several related issues including:
- plain text stories vs pure Ruby (when is which appropriate?)
- extending the RailsStory with custom helpers
- testing forms using webrat within the Story Runner
- finding a balance of domain and UI scenarios
- duplication between stories/scenarios and model/view/controller/helper examples
That’s probably already more than I can cover fairly in a 45 minute presentation, but feel free to make other suggestions if you have them.
See you in Portland!
Advanced Rails Recipes
January 4th, 2008
I’m pleased to announce that my contribution to Mike Clark’s new Advanced Rails Recipes book has been accepted and released. The book is available right now as a Beta PDF and includes dozens of delicious and nutritious recipes for enhancing your Rails applications and the process of developing them.
This is my first formal publication in the software world [1], and I couldn’t be more pleased than to have it be a Pragmatic Bookshelf [2] publication.
My recipe is entitled Describing Behaviour from the Outside-In With RSpec and it demonstrates the BDD approach to Rails apps starting with the view and working your way down to the controllers, models and database.
There is currently one other BDD recipe: Getting Started with BDD, which uses shoulda. There are also recipes for cooking up mocks, code coverage and html validity. And that’s just the testing related recipes.
There are also dozens of recipes dealing with UI, search, email, console, REST, db enhancements and even more general design improvements.
Like the first Rails Recipes book, this one is a must-have for any serious Rails developer who wants to take it up a notch in creating great web applications with Rails.
[1] My first publication of any kind was back around 1980 when I was a young professional magician. The book is called, simply, Coin Magic, and is a must have for any serious coin magician who wants to take it up a notch (see a trend here?) in presenting awesome feats of magic with ordinary coins. Back then I went by my first and middle name, David Arthur.
[2] The Pragmatic Programmers are also publishing my upcoming book with co-author Aslak Hellesøy, tentatively entitled Behaviour Driven Development in Ruby with RSpec.
RSpec 1.1
December 13th, 2007
The RSpec Development Team is pleased as glug (that’s kind of like punch, but more festive) to announce RSpec-1.1.0.
Thanks to all who have contributed patches over the last few months. Big thanks to Dan North and Brian Takita for their important work on this release. Dan contributed his rbehave framework which is now the Story Runner. Brian patiently did a TON of refactoring around interoperability with Test::Unit, and the result is a much cleaner RSpec core, and a clean adapter model that gets loaded when Test::Unit is on the path.
RSpec 1.1 brings four significant changes for RSpec users:
- The RSpec Story Runner
- Nested Example Groups
- Support for Rails 2.0.1
- Test::Unit interoperability
Story Runner
The RSpec Story Runner is Dan North’s rbehave framework merged into RSpec. The Story Runner is a framework for expressing high level requirements in the form of executable User Stories with Scenarios that represent Customer Acceptance Tests.
RSpec 1.1 also ships with a Ruby on Rails extension called RailsStory, which lets you write executable user stories for your rails apps as well.
Nested Example Groups
Now you can nest groups to organize things a bit better:
describe RubyDeveloper do
before(:each) do
@ruby_developer = RubyDeveloper.new
end
describe "using RSpec 1.1.0" do
before(:each) do
@ruby_developer.use_rspec('1.1.0')
end
it "should be able to nest example groups" do
@ruby_developer.should be_able_to_nest_example_groups
end
end
describe "using RSpec 1.0.1" do
before(:each) do
@ruby_developer.use_rspec('1.0.8')
end
it "should not be able to nest example groups" do
@ruby_developer.should_not be_able_to_nest_example_groups
end
end
end
Running this outputs:
RubyDeveloper using RSpec 1.1.0 - should be able to nest example groups RubyDeveloper using RSpec 1.0.8 - should not be able to nest example groups
== Support for Rails 2.0.1
gem install rails rails myapp ruby script/plugin install http://rspec.rubyforge.org/svn/tags/REL_1_1_0/rspec ruby script/plugin install http://rspec.rubyforge.org/svn/tags/REL_1_1_0/rspec_on_rails script/generate rspec
Test::Unit Interoperability
Contrary to popular belief, Spec::Rails, RSpec’s Ruby on Rails plugin, has been a Test::Unit wrapper since the the 0.7 release in November of 2006. RSpec 1.1 ups the ante though, offering a smooth transition from Test::Unit to RSpec with or without Rails:
1. Start with a TestCase:
require 'test/unit'
class TransitionTest < Test::Unit::TestCase
def test_should_be_smooth
transition = Transition.new(
:from => "Test::Unit::TestCase",
:to => "Spec::ExampleGroup"
)
assert_equal "really smooth", transition.in_practice
end
end
2. Require ‘spec’
require 'test/unit'
require 'spec'
class TransitionTest < Test::Unit::TestCase
def test_should_be_smooth
transition = Transition.new(
:from => "Test::Unit::TestCase",
:to => "Spec::ExampleGroup"
)
assert_equal "really smooth", transition.in_practice
end
end
3. Convert TestCase to ExampleGroup
require 'test/unit'
require 'spec'
describe "transitioning from TestCase to ExampleGroup" do
def test_should_be_smooth
transition = Transition.new(
:from => "Test::Unit::TestCase",
:to => "Spec::ExampleGroup"
)
assert_equal "really smooth", transition.in_practice
end
end
4. Convert test methods to examples
require 'test/unit'
require 'spec'
describe "transitioning from TestCase to ExampleGroup" do
it "should be smooth" do
transition = Transition.new(
:from => "Test::Unit::TestCase",
:to => "Spec::ExampleGroup"
)
assert_equal "really smooth", transition.in_practice
end
end
5. Convert assertions to expectations
require 'test/unit'
require 'spec'
describe "transitioning from TestCase to ExampleGroup" do
it "should be smooth" do
transition = Transition.new(
:from => "Test::Unit::TestCase",
:to => "Spec::ExampleGroup")
transition.in_practice.should == "really smooth"
end
end
6. Un-require test/unit
require 'spec'
describe "transitioning from TestCase to ExampleGroup" do
it "should be smooth" do
transition = Transition.new(
:from => "Test::Unit::TestCase",
:to => "Spec::ExampleGroup"
)
transition.in_practice.should == "really smooth"
end
end
At every one of these steps after step 2, you can run the file with the ruby command and you’ll be getting RSpec’s developer friendly output. This means that you can transition things as gradually as you like: no wholesale changes.
That’s the story. Thanks again to all who contributed and to all who continue do so.
before_action/after_action
November 6th, 2007
A while back there was either a feature request in the rspec tracker, or a suggestion on one of the rspec mailing lists, for a feature to DRY up controller specs.
Read the rest of this entryPlain Text Stories on Rails
October 22nd, 2007
Since my last post on plain text stories, there have already been a few improvements, not the least of which is that it will now work with Rails. Again, this is trunk (rev 2769+) only and experimental.
Here’s a working example from an app that I’m working on:
stories/loginStory: registered user logs in
As a registered user
I want to have to log in
So that only other registered users can see my data
Scenario: user logs in and sees welcome page
Given a user registered with login: foo and password: test
When user logs in with login: foo and password: test
Then user should see the welcome page
Scenario: user logs in with wrong password
Given a user registered with login: foo and password: test
When user logs in with login: foo and password: wrong
Then user should see the login form
And page should include text: There was an error logging in.
Scenario: user logs in with wrong login name
Given a user registered with login: foo and password: test
When user logs in with login: wrong and password: test
Then user should see the login form
And page should include text: There was an error logging in.
[Update: modified to use runner.steps instead of runner.step_matchers]
stories/login.rbrequire File.join(File.dirname(__FILE__), *%w[helper])
run_story :type => RailsStory do |runner|
runner.steps << LoginSteps.new
runner.steps << NavigationSteps.new
runner.load File.expand_path(__FILE__).gsub(".rb","")
end
Here’s what’s new in this example:
- run_story is added to the main object so you don’t have to remember that silly path to the PlainTextStoryRunner which will undoutedbly change!
- run_story accepts arguments, including an options hash, which it will pass to the constructor of the PlainTextStoryRunner (in this case, :type => RailsStory)
- run_story yields the runner, which now supports a load method which you use to tell it where to find the plain text story file.
- run_story … runs the story
Keep your eyes peeled for more updates in the coming days.
template.expects_render
June 27th, 2007
One thing that’s been missing from rspec_on_rails for a while is a clean and consistent way to mock or stub calls to partials from inside partials. In fact, even mocking partials inside non-partial templates has been buggy. For example, let’s say you’re describing a template that should include a partial named ‘_thing’. You might want to do something like this:
assigns[:thing] = thing = Object.new
template.should_receive(:render).with(
:partial => 'thing',
:object => thing
)
render 'things/index.html.erb'
Now if that is the only example in your entire suite that renders ‘things/index.html.erb’, no problem. In other words, in most cases, this is a problem.
The Problem
It turns out that Rails compiles ERB templates in memory the first time they are encountered and continues to use the compiled version throughout a given process. This is a GOOD thing for performance. It is, however, a challenge for testability. Why? Because when we stub methods using rspec, mocha or flexmock, we replace the real methods with implementations from the mocking framework. Those methods are part of what gets compiled. And that means WEIRD STUFF.
If you mock a method in the template and the template gets compiled, then every other access to that template accesses the mocked method (even accesses in other examples). Conversely, if you mock a method in a template that’s already been compiled, well, it just doesn’t get hooked up at all and the mock expectation fails.
The problem with mocking partials inside partials is that a response only has one instance of ActionView::Base, so if you mock one call to render on that instance, you mock them all. This means that you simply can not use a standard mocking framework to mock the call as they are simply not designed to pass some calls on to the real object and intercept others.
RSpec’s Solution
To solve this, I created a proxy that delegates to a mock object, but that mock behaviour is not added to ActionView::Base directly. When ActionView::Base receives #render, it asks the proxy if it is interested in the call based on the arguments that were passed in. If so, it passes it on to the mock proxy for later verification, and otherwise swallows the call, the way a mock normally would. If it is not, however, interested in the call, execution of the render method continues as normal.
I have to confess that this feels a bit dirty. I come from a land of fairly strict rules about what mocks should and should not do, but now live in a land in which a lot of rules I learned before are being challenged. This is the land of Ruby and Rails. And so I grit my teeth, and do what seems pragmatic.
View Examples
The result is that you’ll now be able to do this in View Examples:
assigns[:thing] = thing = Object.new
template.expects_render(:partial => 'thing', :object => thing)
render 'things/index.html.erb'
You can even do this if the thing you’re rendering in the example IS a partial which contains a sub-partial:
thing = Object.new
template.expects_render(:partial => 'thing', :object => thing)
render :partial => 'outer_partial', :locals => {:thing => thing}
Controller Examples too
I also added the same behaviour to controllers in Controller Examples. This essentially restores the old controller.should_render behaviour that we gave up in RSpec 0.9, but with the syntax similar to that in the view examples above:
controller.expects_render(:action => 'login')
get 'index'
Thanks to Jake Scruggs for pairing on this with me. It might not have happened had he not offered to help.
When can I use it?
This is committed to RSpec’s trunk and will be released with RSpec-1.0.6, sometime very soon.
Speaking at The Rails Edge
June 6th, 2007
Mike Mangino of Elevated Rails and I are joining forces to do a talk at The Rails Edge in Chicago in August. We’ll be talking about how to use RSpec and Selenium together to drive the development of Rails applications.
Hope to see you there!
Here’s something that bit me today. I’ll bet it’s documented somewhere, and it makes perfect sense, but maybe I can help you avoid this in case you missed the docs like I did.
The situation
I’m working on an asset management system which includes Categories and Tags, which have a many-to-many relationship expressed by a CategorizedTag model.
class Category < ActiveRecord::Base
has_many :tags, :through => :categorized_tags
has_many :categorized_tags
end
class Tag < ActiveRecord::Base
has_many :categories, :through => :categorized_tags
has_many :categorized_tags
end
class CategorizedTag < ActiveRecord::Base
belongs_to :category
belongs_to :tag
end
The problem
In routes.rb, I wanted to nest tags inside categories:
map.resources :categories do |categories|
categories.resources :tags, :name_prefix => 'categorized_'
end
This seemed fine, but I got a nil-pointer error on categorized_tags_path in a view.
The fix
Guessing that there was a naming conflict with CategorizedTag, I tried this instead (‘category_’ instead of ‘categorized_’):
map.resources :categories do |categories|
categories.resources :tags, :name_prefix => 'category_'
end
Sure enough, category_tags_path worked just fine!
The moral
So make sure that when you use :name_prefix that it doesn’t result in the name of an existing model.
Inferred Controllers and Helpers in Spec::Rails
April 3rd, 2007
Here’s a nice little enhancement in Spec::Rails-0.9.
Up until now, controller examples required that the controller be named:
#the old way
context "Login Controller" do
controller_name :login
...
You’ll still be able to do that, but you’ll also be able to do this:
describe LoginController do
...
... and Spec::Rails will assume that LoginController is what you want to use.
This works for your helper examples as well:
describe PeopleHelper do
...
RSpec plays nice with others
April 1st, 2007
RSpec 0.9 is coming soon, and promises to do a better job of playing nice with others.
RSpec plays nice with you.
There’s a new configuration mechanism inspired by the one in Rails:
Spec::Runner.configure do |config|
config.use_transactional_fixtures = true
#etc
end
This mostly affects Spec::Rails users, but as new features become configurable, this will be the “how”.
RSpec plays nice with mocha.
Update 4/25 – 0.9 will be released with support for flexmock as well as mocha.
Speaking of new configurable features, RSpec 0.9 will play nice with other mock frameworks. The first release is going to support using mocha, but we’re hoping to follow this with support for flexmock as well. So now, in a spec_helper.rb, you can do this:
Spec::Runner.configure do |config|
config.mock_with :mocha
end
This tells RSpec to load up mocha instead of RSpec’s mock framework, Spec::Mocks. One nice thing about using mocha with RSpec is that, in my opinion, the different syntax illuminates the different semantics:
- #expects for pre-action, interaction expectations
- #should for post-action, (typically) state expectations
Sure, we could get similar syntax by aliasing #should_receive, but there are a lot of people who simply prefer mocha or flexmock and we want to invite them all to use RSpec without giving up their preferred mocking framework.
RSpec even plays nice with ‘test/unit’
For some time now, RSpec has allowed you to bring the myriad plugins and add-ons associated with ‘test/unit’ by deriving the binding in which examples are run from Test::Unit::TestCase (like so…)
describe Thing do
inherit Test::Unit::TestCase
#...
end
With RSpec 0.9, we’ve added the reverse: Spec::Expectations and Spec::Matchers made available to your ‘test/unit’ tests with a simple require statement:
require 'test/unit'
require 'spec/test_case_adapter'
class ThingTest < Test::Unit::TestCase
def setup
@thing = Thing.new
end
def test_thing_should_be_friendly
@thing.should be_friendly
end
end
RSpec plays nice with your diet
With RSpec 0.9, RSpec is finally sugar-free!
We’ll miss the underscores that followed #should, and I’m personally grateful to Rich Kilmer for the very, very cool patch that not only allowed us to eliminate all of those nasty dots, but taught me one of my first serious lessons in meta-programming. However, as time went on we discovered that continuing to support that sugar was going to be an ongoing struggle between RSpec and any system it was being used to describe that happened to like #method_missing as much as RSpec did. And so we bid it a bittersweet “adieu”.
Of course, if you’re missing some sweetener, there’s always the natural sweeteners in mocha ….
Describe it with RSpec-0.9. Coming soon to a gems directory near you.
view specs are about to get a whole lot easier
January 20th, 2007
The next release of rspec_on_rails will include a complete port of assert_select. So now you’ll be able to spec your login form like this:
context "login/login" do
setup do
render 'login/login.rhtml'
end
specify "should display login form" do
response.should have_tag("form[action=/login]") {
with_tag("input[type=text][name=email]")
with_tag("input[type=password][name=password]")
with_tag("input[type=submit][value=Login]")
}
end
end
How sweet is that!!!
Trunk-sters out there can do this right now. The rest can expect a release within the next couple of weeks.
rspec.should use_a_little_less_magic
January 10th, 2007
Updated on 21 Jan
One of the great things about Ruby is that it allows common folk like you and me to perform all sorts of magic that would dazzle and amaze the more statically typed of our neighbors.
One of the terrible things about Ruby is that, as the secret gets out, the various magic potions we mix begin to conflict with each other, creating the foul stench of bugs that don’t reveal themselves until someone ELSE does some of their own magic.
The most visible conflict has been between RSpec and Ruby on Rails, both of which usurp method_missing to support some devilishly sexy run-time method creation. The problem comes when RoR follows good guidelines like late-binding, and adds its version of method_missing later in the stack than RSpec does, rendering RSpec’s use of method_missing a bit futile, forcing RSpec to monkey patch Rails in order to work.
Well, this conflict may soon see its end.
Read the rest of this entryclean out init.rb in rspec_on_rails plugin
December 22nd, 2006
There is a conflict between spec/rails and test/unit that prevents you from running tests if specs are loaded up. Previous versions of spec/rails had require statements in init.rb in the plugin’s root directory. This meant that you were ALWAYS loading rspec, even in your dev and production environments.
The current version (0.7.5) relies on ~/spec/spec_helper.rb to require ‘spec/rails’, and init.rb is empty.
If you are working with any previous versions, be sure to clean out your ~/vendor/plugins/rspec_on_rails/init.rb (some versions had that directory as rspec).
Fighting the Urge to Ask
November 26th, 2006
ActiveRecord provides a lot of magic methods that let us get at the properties of a given AR subclass. This is absolutely fantastic news!
Except for one thing.
Read the rest of this entry

