如何使用控制器规范中的spec helper方法发布创建?

时间:2011-05-10 23:50:32

标签: ruby-on-rails rspec helper specifications

我对编程,Rails,Ruby,Rspec等都比较陌生,所以感谢您的帮助!

我的规格很重复,所以我写了一些规范帮助方法。我无法弄清楚如何在我的规格中正确使用它们。具体来说,我有一个带有create:

的用户控制器
  def create
    @user = User.new(params[:user])
    if @user.save
      redirect_to user_path(@user)
    else
      render :action => :new
    end
  end

创建有效用户的规范助手中的一点:

def valid_user_eilif
  @test_image = Rails.root + "spec/fixtures/images/seagull.jpg"
  @file = Rack::Test::UploadedFile.new(@test_image, "image/jpeg")
  user = User.create!(:username => "eilif", :email => "eilif@email.org",
  :image => @file, :bio => "Lots of text that I don't want to write",
  :signature_quote => "Yet more text.")
  user.save!
  user
end

然后在我的用户控制器规范中:

before (:each) do
  post :create, :user => valid_user_eilif
end

it 'should assign user to @user' do
  assigns(:user).should eq(User.last)
end

当我运行规范时,我收到错误:

 Failure/Error: assigns(:user).should eq(User.last)

   expected #<User id: 1, username: "eilif", email: "eilif@email.org", bio: "Lots of text that I don't want to write", signature_quote: "I feel empty.", image_file_name: "seagull.jpg", image_content_type: "image/jpeg", image_file_size: 10475, image_updated_at: "2011-05-10 23:35:55", created_at: "2011-05-10 23:35:56", updated_at: "2011-05-10 23:35:56">
        got #<User id: nil, username: nil, email: nil, bio: nil, signature_quote: nil, image_file_name: nil, image_content_type: nil, image_file_size: nil, image_updated_at: nil, created_at: nil, updated_at: nil>

所以,我认为我错误地发布创建,因为什么都没有创建?这样做的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

理想情况下,控制器规范不应该依赖于能够在数据库中创建行的模型。通过这么简单的操作,您可以模拟出依赖关系:

describe UsersController do
  context "on success" do
    before(:each) do
      @user = mock_model(User,:save=>true)
      User.stub(:new) {@user}
      post :create, :user => {}
    end

    it "redirects" do
      response.should redirect_to(user_path(@user))
    end

    it "assigns" do
      assigns[:user].should == @user
    end
  end
  context "on failure" do
    it "renders 'new'" do
      @user = mock_model(User,:save=>false)
      User.stub(:new) {@user}
      post :create, :user => {}
      response.should render_template "users/new"
    end
  end
end

请注意,规范不会传递params[:user]中的任何内容。这有助于强制关注的MVC分离,由此模型负责处理属性,即。验证,设置关联等等。你不能总是把控制器保持为“瘦”,但尝试一下是个好主意。

答案 1 :(得分:0)

看起来问题是保存后@user没有刷新。试试assigns(:user).reload.should eql(User.last)

但还有一个小问题,那可能还是会失败。您不应该使用post致电:user => valid_user_eilif;您希望用户记录中的属性,而不是实际的用户对象本身。而你实际上是在valid_user_eilif中创建一个新用户,然后让你的控制器再次创建该对象 - 如果你有任何一种独特的约束,你就会发生冲突。

这是使用factory_girl和模拟等内容的好地方。例如,take a look表示我的一个项目如何处理控制器规范。此示例使用factory_girl,Mochashoulda。我将用下面的评论对其进行注释:

describe MembersController, "POST create" do
  before do
    # Factory Girl - builds a record but doesn't save it
    @resource = Factory.build(:member)

    # Mocha expectation - overrides the default "new" behavior and makes it 
    # return our resource from above
    Member.expects(:new).with({}).returns(@resource)

    # Note how we expect it to be called with an empty hash; that's from the
    # `:member` parameter to `post` below.
  end

  context "success" do
    before do
      post :create, :member => {}
    end

    # shoulda matchers - check for a flash message and a redirect
    it { should set_the_flash.to(/successfully created/) }
    it { should redirect_to(member_path(@resource)) }
  end

  context "failure" do
    before do
      # Mocha - To test a failing example in the controller, we override the
      # default `save` behavior and make it return false, otherwise it would
      # be true
      @resource.expects(:save).returns(false)
      post :create, :member => {}
    end

    # shoulda matchers - check for no flash message and re-render the form
    it { should_not set_the_flash }
    it { should render_template(:new) }
  end
end