#157
Apr 13, 2009

RSpec Matchers & Macros

You can improve the readability and remove duplication in RSpec by adding matchers and macros. Learn how in this episode.
Tags: testing tools
Download (39.1 MB, 18:09)
alternative download for iPod & Apple TV (25.7 MB, 18:09)

Resources

Note: Unfortunately there are a couple problems with this episode. Special thanks to David Chelimsky for pointing them out.

  1. Since RSpec 1.2.0, the method names for failure messages are failure_message_for_should and failure_message_for_should_not. The old method names are still supported, but will be deprecating
    eventually. The code below has been updated to reflect the new method names.
  2. Newer versions of RSpec offers a 3rd method for creating a custom matcher. We can apply it to this example and it would have proper error messages. Please see the documentation for details on how this works.
# spec_helper.rb
require File.dirname(__FILE__) + "/custom_matchers"
require File.dirname(__FILE__) + "/controller_macros"
# ...
config.include(CustomMatchers)
config.include(ControllerMacros, :type => :controller)

# spec/custom_matcher.rb
module CustomMatchers
  class OneMoreThan
    def initialize(expected)
      @expected = expected
    end

    def matches?(actual)
      @actual = actual
      @actual == @expected+1
    end

    def failure_message_for_should
      "expected #{@actual.inspect} to be one more than #{@expected.inspect}"
    end

    def failure_message_for_should_not
      "expected #{@actual.inspect} not to be one more than #{@expected.inspect}"
    end
  end

  def be_one_more_than(expected)
    OneMoreThan.new(expected)
  end
end

# spec/controller_macros.rb
module ControllerMacros
  def self.included(base)
    base.extend(ClassMethods)
  end
  
  module ClassMethods
    def it_should_require_admin_for_actions(*actions)
      actions.each do |action|
        it "#{action} action should require admin" do
          get action, :id => 1
          response.should redirect_to(login_url)
          flash[:error].should == "Unauthorized Access"
        end
      end
    end
  end
  
  def login_as_admin
    user = User.new(:username => "admin", :email => "admin@example.com", :password => "secret")
    user.admin = true
    user.save!
    session[:user_id] = user.id
  end
end

# article_spec.rb
article2.position.should be_one_more_than(article1.position)

# articles_controller_spec.rb
it_should_require_admin_for_actions :new, :create, :edit, :update, :destroy

# simple matcher
def be_one_more_than(number)
  simple_matcher("one more than #{number}") { |actual| actual == number+1 }
end

RSS Feed for Episode Comments 25 comments

1. mike Apr 13, 2009 at 02:37

Do you do any testing with shoulda? after banging my head over rspec for the past few days i decided to give it a try but there is not much instruction out there. I bet this cast would have gotten me stick with rspec for a few more days if id seen it earlier. :-p


2. Clemens Kofler Apr 13, 2009 at 04:40

It should probably be noted that it's not ideal to just get every passed in action in the last macro. Instead, one might use something like the following:

http://gist.github.com/94405


3. Hongli Lai Apr 13, 2009 at 06:18

Good stuff. :) The RSpec RDoc on matchers is very confusing but your screencast is very easy to understand.


4. Jesse Newland Apr 13, 2009 at 08:54

Awesome, custom rspec matchers for Moonshine are in my backlog. You just saved me a lot of time :).


5. George Apr 13, 2009 at 09:19

Thank you very much.


6. erik Apr 13, 2009 at 10:00

Does your it_should_require_admin_for_actions test what you want it to?

In articles_controller_spec.rb, you wrote out 5 it blocks that test the actions using get, post, put, and delete, but it_should_require_admin_for_actions only runs get on each of the actions. Doesn't it need to run the correct verb on each action, or does it work the way it is?


7. Ryan Bates Apr 13, 2009 at 22:40

@Clemens, @erik, good eye, and thank you for pointing this out. I have not found any downside to using "get" at all times for testing this authentication before filter. However the solution Clements gave seems like a great way to handle this issue.


8. Jose Apr 14, 2009 at 08:57

As a new person to tests and RSpec I have a problem getting my head around one thing:

How do the tests you write get integrated back into the code of the application? And how do methods like login_as_admin get used in the application?

If I'm writing code to make tests easier, shouldn't that code also make coding the application easier?


9. Sig Apr 14, 2009 at 13:36

As always awesome reailscast.
I'm going into Rspec+Cucumber and so on right now and those last episodes are really useful.
Hope you are going to make some more on the topic.

Have a good 1 buddy.


10. Andrea Apr 14, 2009 at 15:10

As usual another great screencast, thanks Ryan.
I am especially enjoying all your recent screencasts dedicated to testing as I felt I needed some extra help on this often underestimated aspect of programming.


11. Mazembo Apr 18, 2009 at 07:00

I really appreciate your work. It helps me to improve my skills in Rails. Thanks a lot.


12. dani Apr 20, 2009 at 11:56

thanks! thanks! thanks!


13. Paul Groves Apr 28, 2009 at 06:10

At 3:07 on line 5 in the block 'action' changes to 'actual' - don't really see this as a problem, was just weird - thought I was seeing things till I wound it back.


14. Scott Apr 28, 2009 at 12:48

Great episode as usual.

I'm a little foggy on why it_should_require_admin_for_actions needs to be a class method. Is it because you're using it to generate it-blocks?


15. Марианна May 23, 2009 at 01:01

hey, what's that? i can't understand


16. mdm Jun 13, 2009 at 14:41

Very cool stuff, thanks Ryan.


17. dolly Jun 19, 2009 at 15:52

Thank you very much.Great stuff.


18. Pavlik Jun 27, 2009 at 00:34

As a new person to tests and RSpec I have a problem getting my head around one thing:

How do the tests you write get integrated back into the code of the application? And how do methods like login_as_admin get used in the application?


19. Ionka Jun 30, 2009 at 22:24

Very nice, senk


20. Romasha Jul 02, 2009 at 02:53

As always awesome reailscast.
I'm going into Rspec+Cucumber and so on right now and those last episodes are really useful.
Hope you are going to make some more on the topic.

Have a good 1 buddy.


21. Nadegdushka Jul 16, 2009 at 23:43

Don`t understand what do this code

it "#{action} action should require admin" do
          get action, :id => 1


22. Boba Jul 25, 2009 at 07:37

Very senk!


23. Daniel Nov 27, 2009 at 05:38

Thanks! Recently I've been reading the RSpec beta book from Pragmatic Programmers, and it was not too much clear for me. Now I think I've finally understood how this works.


24. calc-x Dec 19, 2009 at 08:59

Thank you very much


25. low puma shoes Feb 05, 2010 at 00:32

thank you very much!!


26. ユナイテッド航空 マイレージ May 05, 2010 at 00:15

Thanks! Recently I've been reading the RSpec beta book from Pragmatic Programmers, and it was not too much clear for me. Now I th


27. سعودي كول May 28, 2010 at 19:16

thank you
www.sheshh.com


28. منتديات جديد الورد Jun 18, 2010 at 12:30

www.t-bahlme.com
منتديات جديد الورد برعايه عنتر الوادعي


29. 成人用品 Jun 23, 2010 at 18:48

research on this subject for a school project and your article is really useful


30. timberland uk Jul 04, 2010 at 23:27

I think this is very dangerous


31. generic ativan Jul 10, 2010 at 00:22

In use of the rails of the test, i don't understand.


32. accredited degree Aug 10, 2010 at 21:46

Great informative post thanks for sharing.....


33. free directory list Aug 11, 2010 at 22:34

good idea,i like it


34. cheap air jordans Aug 19, 2010 at 21:01

Awesome, custom rspec matchers for Moonshine are in my backlog. Great informative post thanks for sharing. I really appreciate what you post. If only i could think of a plugin to actually write. I will instantly grab your rss feed to stay informed of any updates.


35. wholesale new era hats Aug 20, 2010 at 20:40

The dissertation chapters should be perfectly composed by distinguished thesis service, when people want to present a writing talent. Thus, this is manifestly that you understand the right way to finish a superb issue referring to this topic. Thank you very much for distributing this.


36. replicahandbags Aug 23, 2010 at 18:06

I have always liked Outdoor movies, a child standing at the window, looked out from home to the following. Will be able to see the staff busy figure, a huge white cloth has a child hang up and soon will be able to see the movie.


37. Air Jordan AJF 3 Aug 24, 2010 at 23:23

I really appreciate what you post. If only i could think of a plugin to actually write. I will instantly grab your rss feed to stay informed of any updates. thank you very much!!


38. Wholesale Electronics Aug 25, 2010 at 02:05

Discount Wholesale Electronics, Wholesale Cell Phones, Electronic Gadgets and More from the Best Dropship Wholesaler


39. louis vuitton shoes Aug 26, 2010 at 21:17

Thanks for sharing your article. I really enjoyed it. I put a link to my site to here so other people can read it. My readers have about the same interets


40. laser poiniter Aug 30, 2010 at 20:01

thanks for sharing, it is so nice.


41. snow boots Aug 30, 2010 at 21:04

Awesome, custom rspec matchers for Moonshine are in my backlog. You just saved me a lot of time :).


42. louis vuitton sunglasses Sep 01, 2010 at 21:27

Good article! Thank you so much for sharing this post.Your views truly open my mind.

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player
Give Back to Open Source