rspec测试协会

发布于 2024-10-26 03:35:29 字数 1438 浏览 1 评论 0原文

我想在我的 rspec 控制器测试中测试员工是否与公司关联。

我想在员工控制器的 create 操作中得到这样的结果:

staff.companies << current_company

其中 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

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

    it "should belong to the current_company" do
      staff.should_receive(:companies)
      post :create
    end

如果我输入 '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.<<

员工控制器创建方法:

  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

I want to test that a staff member is associated with a company in my rspec controller tests.

I would like to end up with this in my create action of the staff controller:

staff.companies << current_company

Where current_company is collected from a session variable.

How do I write a test for this?

I've got these models

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

The following test is my attempt to spec the assocation and it fails when I enter in the association code:

    it "should belong to the current_company" do
      staff.should_receive(:companies)
      post :create
    end

If I enter the 'staff.companies << current_company' code in my controller I get this error when running that test:

 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.<<

Staff controller create method:

  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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

旧伤慢歌 2024-11-02 03:35:29

我会使用不同的方法,因为测试模型应该接收特定消息会使您的测试与实现过于紧密地结合在一起。您真的关心公司是否接收 #<< 或其他方法吗?

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

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

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

I would use a different approach, since testing that the model should receive a certain message couples your tests too tightly to the implementation. Do you really care whether companies receives #<< or some other method?

Really, what you want to test is whether the user's company is recorded when they post to the page. It doesn't matter how it was recorded. So I'd do something like this:

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

This is testing behavior instead of implementation. The advantage is that your test wont fail when someone changes that << to the equivalent push. It also has the advantage of being clearer about your intention and therefore better documenting the code.

以为你会在 2024-11-02 03:35:29

如果您在控制器规范中,我将使用 stub_chain

staff.stub_chain(:company, :<<).once.and_return(true)

它将模拟公司调用和 <<调用并期望它被调用一次。

(至少,.once 应该与stub_chain一起工作......)

If you're in your controller spec, I would use stub_chain

staff.stub_chain(:company, :<<).once.and_return(true)

which will mock out the company call AND the << call AND expect it to be called once.

(At least, that .once should work with stub_chain...)

弱骨蛰伏 2024-11-02 03:35:29

您可以使用以下命令进行测试:

staff.should have(1).company

或者如果该员工已经拥有其他公司,则获取计数并测试 has(count+1).companies。

You can test it with :

staff.should have(1).company

Or if the staff already has other companies, get the count and test for have(count+1).companies.

追星践月 2024-11-02 03:35:29

代码的问题在于,一旦您删除了一个方法,它就不再存在于模型中。

您已经删除了“公司”方法(当您对其设置期望时),现在它不再调用模型上实际的、真实的公司关联,而是您创建的存根...它返回 nil (因为您没有为其设置返回值)。

然后,当您尝试使用 << 将公司放入这个新的 null 方法时它说它不能这样做。

为了解决这个问题,你可以做你所做的事情,即设置一个返回值:

staff.should_receive(:companies).and_return([])

然后将确保:

@staff.companies << current_company

不会因可怕的 nil 错误而失败(因为公司需要进入实际的、真实的数组)。

但真正要做的最好的事情是正如前面的人所建议的那样,并测试您真正需要测试的内容 - 即保存公司员工将导致新公司保存到数据库中。

The problem with the code is that once you stub out a method - it no longer exists on the model anymore.

You have stubbed out the "companies" method (when you set the expectation on it) and it now, no-longer calls the actual, real companies association on the model but the stub that you have created... which returns nil (because you didn't set a returns value on it).

Then, when you try to put a company into this new, null method using << it says it can't do that.

To get around it you can do what you did which is to set a returns value:

staff.should_receive(:companies).and_return([])

which will then make sure that:

@staff.companies << current_company

will not fail with the horrible nil error (because there's and actual, real array for the company to go into).

But really the best thing to do is as the previous people have suggested and test what you actually really need to test - which is that saving a staff with companies will cause a new company to get saved to the db.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文