December 10, 2006

Posted by John

Tagged plugins and testing

Older: Parsing XML With Hpricot

Newer: Pimping Find

BDD and Setting Up Controllers

I started using Rick Olson’s simply_bdd plugin about a month ago. Soon after, I added a method to it and emailed Rick the suggested update. He responded by pointing me to the really sweet test/spec lib and said he may begin using that instead. I gave it a try and fell in love. I like rSpec but I’m not quite ready to jump on the band wagon. test/spec gives me bdd style contexts and specifications while still allowing me to use the assertions from test/unit.

The first thing I noticed as I switched mindsets from tests to specs is that I end up with several smaller contexts as opposed to one massive test case. For unit tests, this doesn’t really change much but with functional tests it does as there is typically more setup. I’m still trying to figure out my “default” contexts for controllers but whatever the case, I always have at least 4 or 5 contexts per controller. Each of these contexts has to setup the controller like so:

context "Some Context" do
  setup do 
    @controller = SomeController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
    # get, post, put or delete some action or whatever else i need for the context ...
  end
end

I know there are arguments for and against repeating yourself in your tests. Some people think it’s horrible, others don’t care. Personally, I just hate typing (and even copying) large amounts of text. Now, I always add the following method to my test_helper.rb file:

def setup_controller(controller)
  @controller = controller.new
  @request    = ActionController::TestRequest.new
  @response   = ActionController::TestResponse.new
end

Now my setup method looks like this:

context "Some Context" do
  setup do 
    setup_controller(SomeController)
    # get, post, put or delete some action or whatever else i need for the context ...
  end
end

One line replaces three. This may not seem like a big deal but when you hate typing as much as me, it comes in pretty handy. I have a plugin I always install which has all my typical test helpers (including this one) and you can grab it from svn.

Update: The test_spec_on_rails plugin has a use_controller method that pretty much negates this post.

4 Comments

  1. John,

    rspec_on_rails actually takes care of this duplication for you:


    context “Some Context” do
    controller_name :articles

    setup do


    1. get, post, put or delete some action or whatever else i need for the context …
      end
      end

I’ll be presenting more on Rspec at the Grand Rapids Ruby Group’s January meeting. I’d love to see you there.

  • It’s nice to see these concepts catching on, but beware of the BDD Cargo Cult

  • @Brandon – I just may. I’ll put it on my calendar. We’ll see how busy I am once it rolls around.

    @Aslak – I’m aware. If it was just me on an island programming apps to count my coconuts, I’d be on rspec but I’m just waiting for it to be more widely used in the rails community. The cool thing is test/spec generates the docs like rspec and adds something.should.be.nil, etc. type syntax so the test code is more friendly similar to rspec.

    You do have me on mock objects though. :) I’m betting that I’ll be on rspec for too long but for now, in the transition period, I’m enjoying test/spec.

  • Here’s a method that doesn’t require passing in the controller at all, at least w/i a test case. I’m not sure how it would be done within specs that don’t have a containing class.

    
      # keep the setup for functional tests DRY
      def setup_functional(controller_klass = controller_class)
        @controller = controller_klass.new
        @request    = ActionController::TestRequest.new
        @response   = ActionController::TestResponse.new
      end
      
      # figure out the controller class name, and cache it in a class level variable
      def controller_class
        @controller_class ||= "#{self.class}".gsub(/Test/, "")
        # logger.debug "controller class: #{@controller_class}"
        Object::const_get(@controller_class.to_sym)
      end
    

  • Sorry, comments are closed for this article to ease the burden of pruning spam.

    About

    Authored by John Nunemaker (Noo-neh-maker), a programmer who has fallen deeply in love with Ruby. Learn More.

    Projects

    Flipper
    Release your software more often with fewer problems.
    Flip your features.