我有两个类OneClass和AnotherClass:
class OneClass
def initialize(*args)
@another_member = AnotherClass.new()
end
def my_method()
if @another_member.another_method1() then
@another_member.another_method2()
end
@another_member.another_method3()
end
end
Run Code Online (Sandbox Code Playgroud)
我正在写单位OneClass.我怎么能嘲笑@another_member?
您不能模拟实例变量。您只能模拟方法。一种选择是在内部定义一个方法OneClass来包装another_member,并模拟该方法。
class OneClass
def initialize(*args)
end
def my_method()
if another_member.another_method1() then
another_member.another_method2()
end
another_member.another_method3()
end
private
def another_member
@another_member ||= AnotherClass.new()
end
end
Run Code Online (Sandbox Code Playgroud)
但是,您不必这样做,有更好的方法来编写和测试您的代码。在这种情况下,更好的模拟方法是使用称为Dependency Injection的模式。
您将依赖项传递给初始化程序。
class OneClass
def initialize(another: AnotherClass, whatever:, somethingelse:)
@another_member = another.new()
end
def my_method()
if @another_member.another_method1() then
@another_member.another_method2()
end
@another_member.another_method3()
end
end
Run Code Online (Sandbox Code Playgroud)
(注意我使用了关键字参数,但您不必这样做。您也可以使用标准的 args 方法)。
然后,在测试套件中,您只需提供测试对象。
let(:test_another) {
Class.new do
def another_method1
:foo
end
def another_method2
:bar
end
def another_method3
:baz
end
end
}
it "does something" do
subject = OneClass.new(another: test_another)
# ...
end
Run Code Online (Sandbox Code Playgroud)
这种方法有几个优点。特别是,您避免在测试中使用模拟,而是真正独立地测试对象。
有了安东尼的想法,我让它发挥作用。
describe OneClass do
before(:each) { @one_object = OneClass.new }
describe 'my_method' do
it 'should work' do
mock_member = double
allow(mock_member).to receive(:another_method1).and_return(true)
@one_object.instance_variable_set(:@another_member, mock_member)
@one_object.my_method()
expect(mock_member).to have_received(:another_method1)
end
end
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3793 次 |
| 最近记录: |