Posted by Dan Croak
Sep
30
Lots of shoulda news to report. The 2.0.x gem has been released, which includes bug fixes, new features, and deprecations.
Rails 2.1+ install
The gem is being hosted at github.com/thoughtbot/shoulda
Specify the gem dependency in your config/environment.rb file:
1
2
3
|
Rails::Initializer.run do |config|
config.gem 'thoughtbot-shoulda', :lib => 'shoulda/rails', :source => "http://gems.github.com"
end |
Then:
1
2
|
rake gems:install
rake gems:unpack |
Now 100% gem
Listen… if you’re still a plugin, I look at you (I’m looking at you, Paperclip), shake my head, and say, “So much untapped potential. Could’ve been big.”
Why gems?
- Ruby comes with a packaging system. No need for another, especially with the gem support in Rails 2.1.
- It’s nice to scan the vendor/gems listing and see version numbers.
- github has excellent gem support.
- In shoulda’s case, it’s a project that can be used in and out of Rails. It’s a pain to have both a plugin and a gem.
Ryan McGeary and Josh Nichols did the bulk of this conversion and related refactoring. They deserve extra acclaim because they’ve made it easier for everyone to contribute to shoulda.
Improvements to current macros
should_assign_to now takes an :equals option. This is now the preferred way to use should_assign_to for edit, show, update, and destroy actions because it is a better test when you explicitly compare assigns(:user) to an expected object.
|
should_assign_to :user, :equals => "@user" |
should_assign_to also now takes a :class option. This is especially good for new actions.
|
should_assign_to :user, :class => User |
should_have_one now supports the :dependent option.
|
should_have_one :address, :dependent => :destroy |
ActiveRecord::Errors.default_error_messages is used instead of home-brewed regexes for all Active Record macros.
New Macros
should_change creates a test asserting a change between the return value of an expression that is run before and after the current setup block is run. This is similar to Active Support’s
assert_difference assertion, but supports more than just numeric values.
1
2
3
4
5
6
7
8
|
context "Creating a post"
setup { Post.create }
should_change "Post.count", :by => 1
end
# :from and :to examples
should_change "Post.count", :from => 0, :to => 1
should_change "@post.title", :from => "old", :to => "new" |
should_not_change creates a test asserting no change between the return value of an expression that is run before and after the current setup block is run.
1
2
3
4
|
context "Updating a post"
setup { @post.update_attributes(:title => "new") }
should_not_change "Post.count"
end |
should_filter_params creates a test asserting that filter_parameter_logging is set for the specified keys
|
should_filter_params :password, :ssn |
should_render_with_layout creates a test asserting that the controller rendered with the given layout.
1
2
3
|
should_render_with_layout # defaults to application
should_render_with_layout 'special'
should_render_without_layout |
should_route creates a routing test. It tries to use the given
HTTP method on the given path, and asserts that it routes to the given options.
1
2
3
4
|
should_route :get, "/posts", :controller => :posts, :action => :index
should_route :delete, "/posts/1", :action => :destroy, :id => 1
should_route :get, "/users/1/posts/1",
:action => :show, :id => 1, :user_id => 1 |
should_respond_with_content_type creates a test asserting that the response content type was ‘content_type’.
1
2
3
|
should_respond_with_content_type 'application/rss+xml'
should_respond_with_content_type :rss
should_respond_with_content_type /rss/ |
should_return_from_session creates a test asserting that a value returned from the session is correct. The given string is evaled to produce the resulting redirect path. All of the instance variables set by the controller are available to the evaled string.
|
should_return_from_session :user_id, "@user.id" |
Before statements
Before statements are should statements that run before the current context’s setup. These are especially useful when setting expectations.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class UserControllerTest < Test::Unit::TestCase
context "the index action" do
setup do
@users = [Factory(:user)]
User.stubs(:find).returns(@users)
end
context "on GET" do
setup { get :index }
should_respond_with :success
# runs before "get :index"
before_should "find all users" do
User.expects(:find).with(:all).returns(@users)
end
end
end
end |
Automatically load custom macros
Writing custom macros is a common practice for The Modern Shoulda Developer. For example, should_have_attached_file used to be a handy custom macro to have around when you’re using Paperclip.
There were a few problems with that, however. Where should that macro go? RAILS_ROOT/test/test_helper.rb? Why do we have the same macro in multiple apps for the same plugin?
Enter the new shoulda_macros directory. Shoulda will automatically load custom macros she finds in:
- RAILS_ROOT/test/shoulda_macros
- RAILS_ROOT/vendor/gems/#{gem_name}/shoulda_macros
- RAILS_ROOT/vendor/plugins/#{plugin_name}/shoulda_macros
Now, every Paperclip user can use the latest should_have_attached_file because it is where it belongs.
should_be_restful is being deprecated
should_be_restful will be removed in a future release. It is currently in a grace period where you’ll see a warning during your test runs. It will be added to the new woulda gem if you care to keep using it. Its problems:
- It dissuades the programmer from good TDD practice. It’s working at too high level of abstraction and encourages the programmer to take too many big steps.
- It is an attempt to be like Rails scaffolding, which is a good way to learn REST, but the syntax is so cryptic it doesn’t accomplish that goal.
- It’s near impossible to find the line in your test file that is actually failing or erroring.
- You have no idea how many tests it generates or how they’re implemented, which lulls the programmer into a false sense of security.
Removed
- load_all_fixtures (use fixtures :all instead)
- shoulda.conf and color support (use the redgreen gem instead)
Credit
Ryan McGeary, Matt Jankowski, Mike Boone, Tammer Saleh, Josh Nichols, Joe Ferris, Keith Morrison, Me
Comments on this post
Sep 30
Ben Scofield said,
Do you all have a solution for the known issues with rake tasks in gemified plugins? If not, then you’re a bit premature in shaking your head at plugins that (so far) eschew the gem route.
Sep 30
Ben Scofield said,
Sorry, I should have added: awesome! I love Shoulda, and am excited to see the update :)
Sep 30
Pablo Formoso said,
Another time, thx. Awsome work!
Sep 30
Steve said,
I’m still getting the “can’t activate activesupport (>= 2.0, runtime), already activated activesupport-2.1.1” when I load my app. I can fix this by manually editing the gem, have you seen this before or know of a solution other than manually editing?
Sep 30
Dan Croak said,
Update:
I had a typo in my original install instructions, which is fixed in the post. Note that the lib needs to be “shoulda/rails”, not “shoulda”. If you run your tests and it can’t find the macros, that’s the cause.
Sep 30
Ryan McGeary said,
Dan, Nice write-up. It covers the recent changesets really well.
Sep 30
Dan Quotes said,
great code and great gem!
Thanks
Sep 30
Josh Nichols said,
To use the rake tasks, do something like:
@ruby begin require ‘shoulda/tasks’; rescue LoadError; end@Sep 30
Dr Nic said,
should_change– you make me cry a little bit with happiness.Oct 01
Barry Hess said,
Thanks for the update. This is actually the first time I’ve actively used Shoulda – it’s great.
Wanted to let you know that I’m getting an undefined method for should_filter_params.
<filter:code> undefined method `should_filter_params’ for SessionsControllerTest:Class (NoMethodError) </fliter:code>Oct 01
Dean Strelau said,
Barry: It looks like
should_filter_paramswas added after the 2.0.2 version bump, so you won’t get it by installing the gem.Hey, Giant Robots: Think we can get a 2.0.3 release with the
should_filter_paramsmacro in there?Oct 02
Justin said,
After removing the plugin and updating to the gem I am getting tons of errors in my tests like this:
“%{fn} can’t be blank” not found in [“Last name can’t be blank”] when set to nil.
Did something change in should_require_attributes?
Thanks
Oct 04
Chris O'Sullivan said,
before_should is flippin’ genius!
Get those pesky expectations RIGHT out of my context setup
Oct 07
Dan Croak said,
@Barry, @Dean Strelau
Thanks for the catch. We just bumped the gem to 2.0.3 so
should_filter_paramsis now properly in the shoulda gem.We received a number of reports that people were typing
:lib => 'shoulda'in theirconfig.gemline. Figuring:lib => 'shoulda/rails'was not intuitive, we added a fix that makes:lib => 'shoulda/rails'work, too.Sorry, comments are closed for this article.
© 2000 - 2009 by thoughtbot, inc.
written by a bushel of tiny robots
Come “ride the toad” on Hoptoad, the app error app.
Thunder Thimble: Brand monitoring for social media.
Widgetfinger: Simple content management for simple websites.
Tee-Bot, funny shirts your friends won't understand!
Umbrella Today: “It’s like totally the simplest weather report ever, Julie.”
Thoughtbot
thoughtbot is a technology consulting firm that provides web application development and design services. We focus on building modern systems, embracing good ideas and delivering elegant solutions.
Interested in learning Rails?
Sign up for our beginning or advanced training.
Archives