rspec测试协会

map*_*ap7 8 rspec2 ruby-on-rails-3

我想在我的rspec控制器测试中测试一名工作人员是否与公司相关联.

我想create在员工控制员的行动中最终得到这个:

staff.companies << current_company
Run Code Online (Sandbox Code Playgroud)

current_company从一个会话变量收集.

我该如何为此编写测试?

我有这些型号

class Company < ActiveRecord::Base
  has_many :employees
  has_many :staff, :through => :employees
end

class Employee < ActiveRecord::Base
  belongs_to :company
  belongs_to :staff
end

class Staff < ActiveRecord::Base
  has_many :employees
  has_many :companies, :through => :employees
end
Run Code Online (Sandbox Code Playgroud)

以下测试是我尝试指定关联,当我输入关联代码时它失败:

    it "should belong to the current_company" do
      staff.should_receive(:companies)
      post :create
    end
Run Code Online (Sandbox Code Playgroud)

如果我在控制器中输入'staff.companies << current_company'代码,运行该测试时会出现此错误:

 Failure/Error: post :create
 NoMethodError:
   You have a nil object when you didn't expect it!
   You might have expected an instance of Array.
   The error occurred while evaluating nil.<<
Run Code Online (Sandbox Code Playgroud)

员工控制器创建方法:

  def create
    @staff = Staff.new(params[:staff])

    if @staff.save
      @staff.companies << current_company
      redirect_to staff_index_path, :notice => "Staff created successfully!"
    else
      @company = @staff.firm || current_company
      flash[:alert] = "Staff failed to create"
      render "new"
    end
  end
Run Code Online (Sandbox Code Playgroud)

Ian*_*Ian 14

我会使用不同的方法,因为测试模型应该收到某个消息会将测试与实现过于紧密地联系在一起.您真的关心公司是否收到#<<或其他方法?

实际上,您要测试的是用户的公司在发布到页面时是否被记录.如何录制并不重要.所以我会做这样的事情:

it "should add the company to the user's list of companies" do
  lambda do 
    post :create
  end.should change(staff.companies, :count).from(0).to(1)
  staff.companies.map(&:name).should include("Acme, Inc.")
end
Run Code Online (Sandbox Code Playgroud)

这是测试行为而不是实现.优点是当有人将其更改<<为等效时,您的测试不会失败push.它还具有更清晰的意图,因此更好地记录代码的优点.