RSpec 3 最佳实践和 Rails 中的 expect_any_instance_of [英] RSpec 3 best practices and expect_any_instance_of in Rails
问题描述
我正在寻找 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屋!