【问题标题】:How to post to create with spec helper method in controller spec?如何发布以在控制器规范中使用规范辅助方法创建?
【发布时间】:2011-05-10 23:50:31
【问题描述】:

我对编程、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>

所以,我假设我错误地发布创建,因为没有创建任何东西?这样做的正确方法是什么?

【问题讨论】:

    标签: ruby-on-rails rspec helper specifications


    【解决方案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 关注点分离,从而模型负责处理属性,即。验证、建立关联等。您不能总是让控制器保持这么“瘦”,但尝试一下是个好主意。

    【讨论】:

      【解决方案2】:

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

      但是还有另一个小问题,而且很可能还是会失败。你不应该用:user =&gt; valid_user_eilif 打电话给post;您想要用户记录中的 属性,而不是实际的用户对象本身。你实际上是在valid_user_eilif 中创建一个新用户,然后让你的控制器再次创建该对象——如果你有任何独特的约束,你就会遇到冲突。

      这是使用 factory_girl 和模拟的好地方。例如,take a look 我的一个项目如何处理控制器规范。此示例使用 factory_girl、Mochashoulda。我将在下面用 cmets 注释它:

      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
      

      【讨论】:

      • 感谢您的建议。我要去看看工厂女孩。同时,根据您所说的属性,我将其更改为: post :create, :user => valid_user_eilif.attributes 并且测试通过了。不过,确实,用户是双重创建的,感觉很草率。猜猜我会花时间在工具箱中添加另一个工具,然后看看我是否可以更智能地处理这个问题。再次感谢。
      猜你喜欢
      • 2021-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多