RSpec 3 最佳实践和 Rails 中的 expect_any_instance_of [英] RSpec 3 best practices and expect_any_instance_of in Rails

查看:38
本文介绍了RSpec 3 最佳实践和 Rails 中的 expect_any_instance_of的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找 expect_any_instance_of 的最佳实践替代方案,因为 RSpec 文档不鼓励使用 expect_any_instance_of:

I'm looking for best-practice alternatives to expect_any_instance_of, because the RSpec documentation discourages using expect_any_instance_of:

此功能在处理遗留代码时有时很有用,但通常我们出于多种原因不鼓励使用它:... [参考]

This feature is sometimes useful when working with legacy code, though in general we discourage its use for a number of reasons: ... [reference]

我经常使用 expect_any_instance_of 来测试在满足某些条件时会调用方法,但对象将在不同的范围内加载.

I use expect_any_instance_of a lot in cases where I want to test that a method will be called when certain conditions are met, but where the object will be loaded in a different scope.

例如,在编写控制器规范时,我只想测试是否在 X 实例上使用正确的参数调用了正确的方法.

For example, when writing a controller spec, I simply want to test that the correct method is called with the correct parameters on an instance of X.

推荐答案

好的,好的.答案是 - 这取决于:)

Ok, well. The answer is - it depends :)

以下内容可能对您有所帮助:

Here are some things, that may help you:

1) 看看您测试代码的方式.(通常)有两种方法可以做到这一点.

假设你有这个类:

class UserUpdater
  def update(user)
    user.update_attributes(updated: true)
  end
end

那么你可以通过两种方式进行测试:

Then you can test it in two ways:

存根一切:

it 'test it' do
  user = double(:user, update_attributes: true)
  expect(user).to receive(:update_attributes).with(updated: true)
  UserUpdater.new.update(user)
end

最少(或没有)存根:

let(:user) { FactoryGirl.create(:user) }
let(:update) { UserUpdater.new.update(user) }

it { expect { update }.to change { user.reload.updated }.to(true) }

我更喜欢第二种方式 - 因为它更自然,让我对测试更有信心.

I prefer the second way - because it is more natural and gives me much more confidence in my tests.

回到您的示例 - 您确定要在控制器操作运行时检查方法调用吗?在我看来 - 最好检查结果.它背后的所有内容都应该单独测试——例如,如果你的控制器有一个服务被调用——你将在它自己的规范中测试关于这个服务的所有内容,以及控制器规范中操作的一般工作方式(某种集成测试).

Back to your example - are you sure that you want to check the method call when the controller action runs? In my opinion - it is better to check the result. Everything behind it should be tested separately - for example, if your controller has a service called - you will test everything about this service in it's own spec, and how the action works in general (some kind of integration tests) in the controller spec.

2.检查返回的内容,而不是它的工作原理:

例如,您有一项服务,可以为您查找或构建用户:

For example, you have a service, which can find or build a user for you:

class CoolUserFinder
   def initialize(email)
      @email = email
   end

   def find_or_initialize
      find || initialize
   end

   private

   def find
     User.find_by(email: email, role: 'cool_guy')
   end

   def initialize
     user = User.new(email: email)
     user.maybe_cool_guy!

     user
   end
end

而且您无需在任何实例上存根即可对其进行测试:

And you can test it without stubbing on any instance:

let(:service) { described_class.new(email) }
let(:email) { 'foo@bar.org' }
let(:user) { service.find_or_initialize }

context 'when user does not exist' do
  it { expect(user).to be_a User }
  it { expect(user).to be_new_record }
  it { expect(user.email).to eq 'foo@bar.org' }
  it { expect(user.role).to eq 'maybe_cool_guy' }
  it { expect(user).to be_on_hold }
end

context 'when user already exists' do
  let!(:old_user) { create :user, email: email }

  it { expect(user).to be_a User }
  it { expect(user).not_to be_new_record }
  it { expect(user).to eq old_user }
  it { expect(user.role).to eq 'cool_guy' }
  it { expect(user).not_to be_on_hold }
end

3.最后,有时您真的需要存根任何实例.没关系 - 有时会发生狗屎:)

有时你也可以像这样用存根替换 any_instance:

Sometimes you can also replace any_instance with stub like this:

allow(File).to receive(:open).and_return(my_file_double)

希望对你有所帮助,希望不会太长:)

I hope it will help you a bit and I hope it is not too long :)

这篇关于RSpec 3 最佳实践和 Rails 中的 expect_any_instance_of的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆