views:

99

answers:

1

Hey all, I am completely lost on this one.

I found a code snippet online to help validate fields via ajax as the user types into them. So I'm trying to write a spec against part of it and I just can't get it to pass.

Here's the code

def validate
  field = params[:field]
  user = User.new(field => params[:value])
  output = ""
  user.valid?
  if user.errors[field] != nil
    if user.errors[field].class == String
      output = "#{field.titleize} #{user.errors[field]}" 
    else
      output = "#{field.titleize} #{user.errors[field].to_sentence}" 
    end
  end
  render :text => output
end

and here is my test so far

  describe "POST validate" do
    it "retrieves the user based on the past in username" do
      mock_errors ||= mock("errors")
      mock_errors.stub!(:[]).and_return(nil)
      User.should_receive(:new).with({'username'=>"UserName"}).and_return(mock_user)
      mock_user.should_receive(:valid?).and_return(true)
      mock_errors.should_receive(:[]).with("username").and_return(nil)
      put :validate, :field=>'username', :value=>'UserName'      
      response.should == ""
    end
  end

I get this error -

1) Spec::Mocks::MockExpectationError in 'UsersController POST validate retrieves the user based on the past in username' Mock 'errors' received unexpected message :[] with ("username")

I can't seem to figure out how in the world to mock the call to user.errors[field]. Ideally this spec tests the happy path, no errors. I'll then write another for a validation failure.

+1  A: 

I'm not seeing mock_user. Here's a shot at it:

describe "POST validate" do
  it "retrieves the user based on the past in username" do
    mock_errors = mock("errors")
    mock_user = mock("user")
    mock_user.stub!(:errors).and_return([mock_errors])
    mock_errors.stub!(:[]).and_return(nil)
    User.should_receive(:new).with({'username'=>"UserName"}).and_return(mock_user)
    mock_user.should_receive(:valid?).and_return(true)
    mock_errors.should_receive(:[]).with("username").and_return(ActiveRecord::Errors.new({}))
    put :validate, :field=>'username', :value=>'UserName'      
    response.should == ""
  end
end

The key is that you need your User mock to respond to the errors method by returning either an empty hash or a hash of fieldname/errors. An alternative to this is to use one of the fixture replacement tools. I'm using machinist right now, which might reduce this whole thing to:

describe "POST validate" do
  it "retrieves the user based on the past in username" do
    @user = User.make{'username'=>"UserName"}
    @user.should_receive(:valid?).and_return(true)
    @user.errors.should_receive(:[]).with("username").and_return(ActiveRecord::Errors.new({}))
    put :validate, :field=>'username', :value=>'UserName'      
    response.should == ""
  end
end
Steve