我正在学习rspec,我想知道为一个调用其他方法链的方法编写规范的最有效方法。例如:
class Example1
def foo(dependency)
dependency.bar("A")
dependency.baz("B")
dependency.bzz("C")
end
end
理想情况下,我想写这样的规格:
it "should call bar" do
ex = Example1.new
dep = mock
dep.should_receive(:bar).with("A")
ex.foo(dep)
end
it "should call baz"
...
it "should call bzz"
...
然而,当我这样做时,我(可以理解)得到像'意外的方法调用baz'之类的例外。
那么处理这个问题的最佳方法是什么?我想出了一些想法,但我不知道它们中是否有任何好处。
答案 0 :(得分:1)
RSpec有一个名为stub_chain的功能:https://www.relishapp.com/rspec/rspec-mocks/v/2-0/docs/stubs/stub-a-chain-of-methods
如何在一个例子中测试它们呢?
it "should call bar"
ex = Example1.new
dep = mock
dep.should_receive("bar").with("A")
dep.should_receive("baz").with("B")
dep.should_receive("bzz").with("C")
ex.foo(dep)
end
我相信你可以使用RSpec来验证它们被调用的顺序,如果这很重要的话。
然而,这种方法通常表明代码的编写方式存在问题,例如:德米特违法法则。在您的示例中,foo
应该是依赖项的类。
答案 1 :(得分:1)
听起来你已经解决了RSpec给你的选项。我会选择选项1并使用as_null_object
。确实,您可能缺少对该对象的其他随机方法调用,但如果每个测试的要点只是断言正在调用某个特定方法,我会很好,特别是如果我有更高级别的集成测试覆盖这种方法。
如果你真的需要验证在dependency
上没有调用其他方法,那么选项3可能有意义,但是当实现发生变化时,这些测试可能会很脆弱。
顺便说一句,为了使您的测试更简单一点,您可以使用subject
来避免显式实例化Example1
(假设您正在使用describe Example1
块),例如:
subject.foo(dep)
(但是参见评论中的讨论 - 隐含的主题可以隐藏意图)。
答案 2 :(得分:1)
我会用这种方式测试这段代码:
describe "checking foo method" do
before(:each) do
@ex = Example1.new
@test = ClassOfDependency.any_instance
@test.as_null_object
end
after(:each) do
@ex.foo(dependency)
end
it "should call bar method" do
@test.should_receive(:bar).with("A")
end
it "should call baz method" do
@test.should_receive(:baz).with("B")
end
it "should call bzz method" do
@test.should_receive(:bzz).with("C")
end
end
但我不确定它会起作用,希望它会给你一些想法。