Ruby on rails 预期:收到任何参数时为1次:收到任何参数时为0次

Ruby on rails 预期:收到任何参数时为1次:收到任何参数时为0次,ruby-on-rails,rspec,mocking,Ruby On Rails,Rspec,Mocking,我正在测试我的项目控制器的索引操作 我正在使用will_paginate gem,并且正在尝试编写一个RSpec测试,以确保在当前用户的项目中投影_路径时对其调用paginate方法 然而,我得到的结果并不是我所期望的,我也不知道为什么 结果 Failure/Error: expect(user.projects).to receive(:paginate) (#<ActiveRecord::Associations::CollectionProxy::ActiveRecor

我正在测试我的
项目控制器的
索引
操作

我正在使用will_paginate gem,并且正在尝试编写一个RSpec测试,以确保在当前用户的项目中投影_路径时对其调用paginate方法

然而,我得到的结果并不是我所期望的,我也不知道为什么

结果

Failure/Error: expect(user.projects).to receive(:paginate)
       (#<ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Project:0x00000004719ef0>).paginate(any args)
           expected: 1 time with any arguments
           received: 0 times with any arguments
     # ./spec/requests/project_pages_spec.rb:82:in `block (3 levels) in <top (required)>'
describe "index" do

  describe "pagination" do

    let(:user) { FactoryGirl.create(:user) }
    let(:client) { FactoryGirl.create(:client) }

    before do
      capybara_sign_in(user)
      @project = Project.create(name: "Blog", fee: 550, client_id: client.id)
    end 

    it "should call the paginate method" do
      expect(user.projects).to receive(:paginate)
      visit projects_path
    end
  end
end
指数测试

Failure/Error: expect(user.projects).to receive(:paginate)
       (#<ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Project:0x00000004719ef0>).paginate(any args)
           expected: 1 time with any arguments
           received: 0 times with any arguments
     # ./spec/requests/project_pages_spec.rb:82:in `block (3 levels) in <top (required)>'
describe "index" do

  describe "pagination" do

    let(:user) { FactoryGirl.create(:user) }
    let(:client) { FactoryGirl.create(:client) }

    before do
      capybara_sign_in(user)
      @project = Project.create(name: "Blog", fee: 550, client_id: client.id)
    end 

    it "should call the paginate method" do
      expect(user.projects).to receive(:paginate)
      visit projects_path
    end
  end
end
请注意,我还没有完成测试的编写,所以请省略关于:干涸代码等的任何注释


谢谢你们的帮助(男/女!)

失败的原因是spec文件中的
用户
与控制器中的
当前用户
不同。因此,当当前用户
正在接收
paginate
时,您的规范的
用户
永远不会收到。有几种方法可以解决这个问题

您可以这样做:

expect_any_instance_of(User).to receive(:paginate)
这里的缺点是您测试的是任何实例,而不是您的
当前用户
实例。这是否是个问题取决于你:)

另一种方法是存根
当前用户

controller.stub(:current_user).and_return(user)
expect(user.projects).to receive(:paginate)

好处是你测试的是同一个用户。缺点是存根
当前用户
可能会带来其他问题。

您感到的部分痛苦是您正在测试实现而不是行为。一般来说,web请求的行为可以用几句话来描述:它接受输入参数并返回响应。要测试行为,请测试响应的内容

在您的情况下,当存在
params[:search]
时,应用程序将以一种方式运行,当它丢失时,应用程序将以另一种方式运行。因此,编写一个将
params[:search]
设置为适当值的测试,以及一个缺少该值的测试,并测试每种情况下的响应是否符合预期。您不需要检查整个响应,只需检查返回的数据是否正确即可

要使测试返回正确的响应,请为每个测试使用不同的数据集。模型将返回预期的行,瞧!,通过测试


现在看来,这似乎比模拟和存根工作要多,运行起来需要更多的时间,但这是测试请求的正确方法。您需要检查整个堆栈,而不仅仅是控制器中的方法调用。生成的测试将是真正的集成测试,并且不会那么脆弱,因为它们没有与实现耦合。

非常感谢您的回答!我肯定会重做测试,将重点放在行为上,而不是实现上。我没有给你答案的唯一原因是它没有直接解决我的技术问题。不过还是要谢谢你的提示。将付诸实施;)Op没有说他们想要“真正的集成测试”。我知道集成测试展示了更大的功能,但我有点厌倦了人们用批评他们的测试哲学或其他东西来解释RSpec的缺点。自以为是的默认值是一回事,但如果我想测试一个方法是否被调用了N次,那么上帝保佑,我要这么做,试着阻止我。@maxple这不是“RSpec缺点”。RSpec允许您尽情地模仿和存根。如果说有什么问题的话,那就是为Rails控制器编写测试的困难。由于这个原因,我很少编写控制器测试——由于Rails的“魔力”,它们不能作为单独的单元进行测试。如果您打算为Rails编写完整的堆栈测试(您应该这样做),那么控制器测试就没有那么有价值了。@Zettetic我有点把您当作稻草人。但是如果你看看RSpec的github问题,有很多例子表明他们说“我们不允许这样做,因为这不是一个好的设计模式”,然而人们一遍又一遍地访问这些线程并与它们争论。@maxple我认为所有开源项目在某个时候都会遇到这个问题。维护人员对项目有一个愿景,他们促进这个愿景,一些用户推动项目向另一个方向发展。在这类争论中,我通常站在维护人员一边,因为他们最了解如何使用产品。在RSpec的具体案例中,我认为由于它的大部分用途是用于Rails测试,因此许多投诉是不公平的。在Rails之外,RSpec是一件轻而易举的事。在Rails中,它通常看起来很难使用,尽管经过多年的裁剪。。。