有些东西告诉我,我在测试中缺少一个关键概念/想法,或者(天堂禁止)ruby如何初始化对象。
我有一个接受两个参数的类方法,并返回所述类的实例。所以它看起来像这样:
class Manager
def self.run(first_arg, second_arg)
new(first_arg, second_arg)
end
end
这是我的RSpec测试:
RSpec.describe Manager, type: :api do
let(:first_arg) { FactoryGirl.build_stubbed(:first_arg) }
let(:second_arg) { AccountMailer.new }
describe '::run' do
it "accepts two arguments" do
expect(Manager).to receive(:run).with(first_arg, second_arg)
Manager.run(first_arg, second_arg)
end
it "instantiates the class with 2 arguments" do
expect(Manager).to receive(:new).with(first_arg, second_arg)
Manager.run(first_arg, second_arg)
end
end
end
由于(我相信)方法:initialize
被new调用,我将代码更新为:
class Manager
# add attr_reader for read access
attr_reader :first_arg, :second_arg
def initialize(first_arg, second_arg)
@first_arg = first_arg
@second_arg = second_arg
end
def self.run(first_arg, second_arg)
new(first_arg, second_arg)
end
end
我的测试失败并返回此错误:
1) Manager#run instantiates the class
Failure/Error: expect(Manager).to receive(:new).with(first_arg, second_arg)
Wrong number of arguments. Expected 0, got 2.
我的主要问题是:
为什么看起来我传递给初始化的方法没有在rspec中被选中?我希望测试能够通过,因为Manager.new
,如果在类中定义了initialize
,如果没有传递2个参数,则会失败。
任何人都可以指出我在这里缺少的东西吗?感谢您的反馈。谢谢。
答案 0 :(得分:6)
予。我能用这样的代码重新创建你的问题
class Manager
def self.run(a, b)
new(a, b)
end
end
RSpec.configure do |config|
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
end
RSpec.describe Manager, type: :api do
let(:a) { 1 }
let(:b) { 2 }
describe '::run' do
it 'instantiates the class with 2 arguments' do
expect(Manager).to receive(:new).with(a, b)
Manager.run(a, b)
end
end
end
结果是:
1) Manager#run instantiates the class with 2 arguments
Failure/Error: expect(Manager).to receive(:new).with(a, b)
Wrong number of arguments. Expected 0, got 2.
这是因为verifying functionality。启用此设置(应该是)时,RSpec将确保该对象实现了被存根/模拟的接口。在这种情况下,RSpec会在行expect(Manager).to receive(:new).with(a, b)
上抛出一个错误,因为它实际上会查看Manager
类并检查初始化是否可以使用2个参数。
如果您将经理更改为如下所示,则示例将通过:
class Manager
attr_reader :a, :b
def initialize(a, b)
@a = a
@b = b
end
def self.run(a, b)
new(a, b)
end
end
II。但是你真的不需要使用模拟这样的功能。如果您只是检查是否返回了正确类型的实例,那么最好只查看真实的实例。
RSpec.describe Manager, type: :api do
let(:a) { 1 }
let(:b) { 2 }
describe '::run' do
subject { described_class.run(a, b) }
it 'instantiates the class with 2 arguments' do
expect(subject).to be_an_instance_of(Manager)
end
it 'sets a to the first argument' do
expect(subject.a).to eq(a)
end
it 'sets b to the second argument' do
expect(subject.b).to eq(b)
end
end
end
III。在这个例子中:
expect(Manager).to receive(:run).with(first_arg, second_arg)
Manager.run(first_arg, second_arg)
您设置了一个断言,然后立即调用代码来传递该断言。所以没有真正测试任何东西。
正确模拟/存根是相当先进的测试概念,很容易弄错,所以如果你可以不用它,只是不用它,它会让事情变得更容易。
如果您想了解更多有关测试/何时模拟的信息。我推荐Sandi Metz的演讲。 https://www.youtube.com/watch?v=URSWYvyc42M