【问题标题】:Rspec Rails: testing controller method 'create' with a multi-model formRspec Rails:使用多模型形式测试控制器方法“创建”
【发布时间】:2012-06-27 06:21:39
【问题描述】:

我正在使用通常的模型、视图和控制器分类构建一个 Ruby on Rails 应用程序。

我的一个控制器中的“创建”操作应该创建两个不同模型的实例。这是我的代码:

 def create
  @league = League.new(params[:league])
  @user = @league.users.build(params[:user])
  ... .save conditions appended ...
 end

因此,当您通过 LeaguesController 通过对 /leagues 的 POST 请求调用“create”时,您将获得一个新的 League 实例和一个新的 User 实例。我还希望新的 User 实例能够继承新的 League 实例的 ID,因此它可以用作将实例链接在一起的外键。这是通过以下方式完成的:

 def create
  @league = League.new(params[:league])
  @user = @league.users.build(params[:user])
  @league_id = @league.id
  @user.update_attribute('league_id', @league_id)
  ... .save conditions appended ...
 end

用户模型已经belongs_to联盟模型,其中has_many用户。

上面的代码工作得很好,花花公子,通过手动测试验证。但是,我一生都无法弄清楚如何使用 Rspec 自动化这些测试。我正在努力成为一个好孩子并使用测试驱动设计,但这让我很难过。

问题是我无法弄清楚如何在我的测试中访问新创建的 League 和 User 实例的属性。我正在尝试使用以下代码:

describe LeaguesController do
  describe 'new league and user' do
    it 'should create a new user with a league_id equal to the new leagues id'
      @league_attr = { :name => "myleague", :confirmation_code => "mycode", :id => 5}
      @user_attr = { :username => "myname", :password => "mypass"}
      post :create, :user => @user_attr, :league => @league_attr
      assigns(:league_id).should eql(5)
    end
  end
end

但是对于:league_id 的值,测试返回nil

我对一般编程和 Rspec 都是新手,所以我非常感谢有人可能提供的任何帮助!

【问题讨论】:

    标签: ruby-on-rails rspec controller update-attributes


    【解决方案1】:

    您不能将:id 分配给new。试试这个:

     def create
       @league = League.new(params[:league])
       @league.id = params[:league][:id] if params[:league][:id]
       @user = @league.users.build(params[:user])
       @league_id = @league.id
       @user.update_attribute('league_id', @league_id)
       ... .save conditions appended ...
     end
    

    也就是说,我想知道它是如何在浏览器中工作的。

    另外,您最好在测试时使用 FactoryGirl 或 Fixtures 将数据分配给模型。

    【讨论】:

    • 感谢 Wawa Loo 的回复。我认为它有效,因为我实际上不必分配:id。每次创建新模型实例时都会自动分配它。我只是在读取已经存在的值并将其值分配给不同模型实例中的不同属性。
    • 其实一个新的并没有赋值id。必须先保存。我认为它不起作用,因为你在做@user = @league.users.build(params[:user])@league_id = @league.id 行没有任何帮助。 (如果这是您所期望的,请考虑接受答案)
    • 嗯,您的测试正在发挥作用。他们告诉您,您的控制器操作创建存在问题:提供 :id 作为参数并不好,并且在保存 2 个关联模型时,您应该使用另一种方法(事务 - 肯定 - 创建用户,联盟并通过,直到它们正确关联)。
    【解决方案2】:

    你试过pry吗?

    每当我发现这样的事情时,我发现能够通过 Pry(或 Ruby-Debug)插入一个刹车点非常方便,这样我就可以检查变量及其行为。

    我怀疑在@league_id = @league.id@user.update_attribute('league_id', @league_id) 之间添加一个binding.pry 可能会很好地阐明这个问题。

    另请注意,当您通过@league.save 调用持久化@league_id 时,用户将自动继承它。 (这就是 @league.users.build(..) 背后的想法 - 它会在持久性时正确设置所需的关系。

    【讨论】:

    • 谢谢 Tigraine,我会去看看 Pry。我对该方法的工作方式充满信心(它的行为符合预期),但我想使用 Rspec 自动化测试,这样我就可以确保在我的应用程序变得更加复杂时不会破坏这个功能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多