Displaying articles with tag ruby

Frustrations with rSpec

Posted by sam, Sun Feb 24 22:32:00 UTC 2008

I'm working on the new blog, and I'm having some trouble with rSpec testing controllers and nested routes.

Here's my routes file

ActionController::Routing::Routes.draw do |map|
  map.root :controller => "frontpage"
  map.resources :posts, :has_many => :comments 
end 

And here is some of the controller specs I'm trying to test

require File.dirname(__FILE__) + '/../spec_helper'

describe CommentsController do
  describe "handling GET /posts/1/comments" do

    before(:each) do
      @comment = mock_model(Comment)
      Comment.stub!(:find).and_return(@comment)
      @post = mock_model(Post)
      @post.stub!(:comments)
      @post.comments.stub!(:find).and_return([@comment])
      Post.stub!(:find).and_return(@post)
    end

    def do_get
      get :index, :post_id =>@post.id 
    end

    it "should be successful" do
      do_get
      response.should be_success
    end

    it "should render index template" do
      do_get
      response.should render_template('index')
    end

    it "should find all comments" do
      Comment.should_receive(:find).with(:all).and_return([@comment])
      do_get
    end

    it "should assign the found comments for the view" do
      do_get
      assigns[:comments].should == [@comment]
    end
  end

Here's the controller

class CommentsController < ApplicationController
  # GET /comments
  # GET /comments.xml
  before_filter :load_post

  def index
    @comments = @post.comments.find(:all)

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @comments }
    end
  end
  protected 
  def load_post
    @post = Post.find(params[:post_id])
  end
end

Everything works, except for one spec:

When I try to run the spec on "it should find all comments" I get this error

Mock 'Class' expected :find with (:all) once, but received it 0 times

I don't know what to do. I'm trying to understand what I'm doing. Mocks and Stubs are a big leap of faith for someone who grew up using full blown fixtures. I hope my other specs aren't passing due to dumb luck or something like that.

Should I wait and try to do this in the Stories? Is it useful to to rSpec mocks and stubs for a nested resource?

Any ideas? Fire away in the comments.

BTW, I'm using the great article Rolling on Rails with Rails2.0 from Akita on Rails as a starting point for my new blog.

Thanks for the great article!

1 comment | Filed Under: | Tags: ruby

Running Rake tasks inside of rSpec Stories.

Posted by sam, Thu Feb 21 02:04:18 UTC 2008

I've started using rSpec at work for my project. I like it because it just seems better to use than Test::Unit. It also looks nicer.

Anyway, my project at work involves converting data from and old database into a new one by way of CSV files. Its long and tedious, and there are hundreds of thousands of rows hitting several models involved.

Inevitably, something will bomb during the process. I've I've developed a process where I can selectively extract a participant based off of their employee number and create a folder filled with their csv files. However, I wasn't really doing any testing on it at this point. We're using rSpec for model testing, and after watching the rSpec User Story PeepCode, I decided to give it a whirl for on my file conversion process.

I start my file conversion process on a single employee by invoking a rake task. It's basically a batch job.

rake conversion:selective_import id=12345

In order to set this up via rSpec stories, first you need to set up the rspec helper file located in RAILS_ROOT/stories/helper.rb. Insert these lines.

require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'tasks/rails'
load "lib/tasks/conversion/tables/001_employee.rake

You need to manually load a the rake tasks you need for some reason I haven't figured out yet.

Next up, in the story's .rb file, you need to make it look like this

require File.expand_path(File.dirname(__FILE__) + "../../../helper")
with_steps_for(:conversion) do
  run File.join(File.dirname(__FILE__), "conversion_story"), :type => RailsStory
end

Astute readers may wonder why the file is buried so far down: I'm trying to create many stories and i'm organizing them by folder. Here's the edited output from tree

|-- all.rb
|-- helper.rb
|-- scenarios
|   |-- conversion
|   |   |-- conversion_story
|   |   `-- conversion_story.rb
`-- steps
    `-- conversion.rb

My conversion steps look like this:

steps_for(:conversion) do

  Given "a employee number $employee_number" do |employee_number|
    @emp_no = employee_number
  end

  Given "is extracted" do
    #look for the employee's extract in the folder
    #if you dont find it, then run the extraction task
  end

  When "I nuke the database" do
    Rake::Task['conversion:nuke'].invoke
  end

  When "I nuke the employee" do
    ENV['id']=@emp_no
    Rake::Task['conversion:selective_nuke'].invoke
  end

  When "I reset the employee" do
    ENV['id']=@emp_no
    Rake::Task['conversion:selective_reset'].invoke
  end

  When "I convert the employee" do
    ENV['id']=@emp_no
    Rake::Task['conversion:selective_import'].invoke
  end

  Then "there should only be 1 employee" do
    Employee.count.should == 1
  end
end

Obviously, the code at this point is a work in progress, but so far, so good.

Here's the story

Story: File conversion test

    As a user
    I want to convert an employee with 
    So that I can verify that their is only one

  Scenario:  42582

    Given an employee number 42582

        When I nuke the database
        And I convert the employee

        Then there should only be 1 employee

I hope all of you have enjoyed this rSpec tutorial with Rake.

0 comments | Filed Under: | Tags: ruby