RSpec文档显然是opposed to expect_any_instance_of,表示它只应用于遗留代码,因此我正在寻找最佳实践替代方案。
在我想测试在满足某些条件时调用方法但是在不同范围内加载对象的情况下,我会使用expect_any_instance_of。
例如,在编写控制器规范时,我只想测试在X实例上使用正确的参数调用正确的方法。
答案 0 :(得分:1)
有些事情可能会对你有所帮助:
1)看看你测试代码的方式。 (通常)有两种方法可以做到。
假设你有这个课程:
class UserUpdater
def update(user)
user.update_attributes(updated: true)
end
end
然后你可以用两种方式测试它:
留下一切:
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) }
我更喜欢第二种方式 - 因为它更自然,让我对我的测试更有信心。
回到您的示例 - 您确定要在控制器操作运行时检查方法调用吗?在我看来 - 最好检查结果。它背后的所有东西都应该单独测试 - 例如,如果你的控制器有一个叫做的服务 - 你将在它自己的规范中测试这个服务的一切,以及控制器规范中的动作如何工作(某种集成测试)。
例如,您有一个服务,可以为您找到或构建用户:
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
您可以在不对任何实例进行存根的情况下对其进行测试:
let(:service) { described_class.new(email) }
let(:email) { 'foo@bar.org' }
let(:user) { service.find_or_intialize }
context 'when user not exists' 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
有时你也可以用这样的存根替换any_instance:
allow(File).to receive(:open).and_return(my_file_double)
我希望它会对你有所帮助,我希望它不会太久:)