views:

26

answers:

1

Hello all,

I'm very new to rails and I've been following a lot of great tutorials and examples out there in the community, so first off thank you!

I'm having a problem with my test code. The application works, and I can see from tailing the test logs that the database is being written, but for some reason, it's not returning the save method properly.

This is basically right out of Michael Hartl's Rails Tutorial

The "success" cases are returning an "expected save but received it 0 times", and the "failure case redirects to the wrong place. It almost seems like it's ignoring the if/else block.

Here's the relevant code from the controller spec and the controller

I would really appreciate any insight into this.

Thanks, -Joe


class WebsitesController < ApplicationController
  before_filter :require_user, :only => [:new, :edit, :create, :destroy]

  def new
    @website = Website.new
    @title = "Add New Website"
  end

  def edit
    @website = Website.find(params[:id])
    @title = "Edit Website"
  end

  def create
    @website = current_user.websites.build(params[:website])
    if @website.save
      flash[:success] = "Website Added!"
      redirect_to(profile_url)
    else
      render 'new'
      @title = "Add New Website"
    end
  end

  def destroy

  end

end

require 'spec_helper'

describe WebsitesController do
  integrate_views

  describe "POST 'create'" do

    before(:each) do
      activate_authlogic
      @user = Factory(:user)
      UserSession.create(@user, true)
      @attr = {
        :domain => "http://www.example.com",
        :description => "example site"
      }
      @website = Factory(:website, @attr.merge(:user => @user))
      @user.websites.stub!(:build).and_return(@website)
    end

    describe "failure" do

      before(:each) do
        @website.should_receive(:save).and_return(false)
      end

      it "should render the 'new' page" do
        post :create, :website => @attr
        response.should render_template('websites/new')
      end
    end

    describe "success" do

      before(:each) do
         @website.should_receive(:save).and_return(true)
      end

      it "should redirect to the profile page" do
        post :create, :website => @attr
        response.should redirect_to(profile_url)
      end

      it "should have a flash message" do
        post :create, :website => @attr
        flash[:success].should =~ /website added/i
      end
    end
  end
end
A: 

It looks to me like you're using should_receive when you should be using stub. I've struggled with this myself, and have come up with this rule:

use mocks/stubs when you DON'T want to test something
use message expectations when you DO want to test something

In your case you DO want to test that the page is rendered, the request is redirected, and the flash is set. So you set message expectations on those conditions. You DON'T want to test that the model is saved or not saved, so you use stubs for that.

zetetic
Thank you, that seems to solve part of the problem. Although I think something a little more subtle is happening. The failure condition redirects to the same place as the success (only in the tests). It almost seems as though it's ignoring the if/else statement in the controller.
jpoday
Interesting. Does the success action redirect correctly? Is it possible that the `before_filter` is not allowing the save to be reached?
zetetic
The success action does redirect properly. It's very odd. If I remove the if/else completely and just leave a @website.save, all of the tests pass (stubbed or should receive) but then it complains that the views are missing. I think it is the before_filter. I have a feeling that I'm not properly creating the UserSession in the tests.
jpoday
I don't see `include Authlogic::TestCase` -- are you including that in `spec_helper`?I think you can test for the Authlogic session with `current_user.should == @user`.
zetetic
Thanks for your help on this. I did finally figure it out a while ago.I needed "controller.current_user.websites.stub!(:build).and_return(@website)" instead of "@user.websites.stub!(:build).and_return(@website)"
jpoday