Joh*_*gan 5 ruby testing unit-testing rspec ruby-on-rails
我似乎遇到过文献暗示使用 RSpec 的any_instance_of方法是不好的做法(例如expect_any_instance_of)。津津乐道的文档甚至在“使用遗留代码”部分(http://www.relishapp.com/rspec/rspec-mocks/v/3-4/docs/working-with-legacy-code/any -instance ) 这意味着我不应该利用它编写新代码。
我觉得我经常编写依赖此功能的新规范。一个很好的例子是任何创建一个新实例然后调用它的方法的方法。(在 Rails 中,MyModel 是一个 ActiveRecord)我经常编写执行以下操作的方法:
def my_method
my_active_record_model = MyModel.create(my_param: my_val)
my_active_record_model.do_something_productive
end
Run Code Online (Sandbox Code Playgroud)
我通常会写我的规范来寻找do_something_productive使用expect_any_instance_of. 例如:
expect_any_instance_of(MyModel).to receive(:do_something_productive)
subject.my_method
Run Code Online (Sandbox Code Playgroud)
我可以看到的唯一另一种方式是使用一堆这样的存根:
my_double = double('my_model')
expect(MyModel).to receive(:create).and_return(my_double)
expect(my_double).to receive(:do_something_productive)
subject.my_method
Run Code Online (Sandbox Code Playgroud)
但是,我认为这更糟糕,因为 a) 它的书写时间更长且速度更慢,并且 b) 它比第一种方式更脆弱和更白盒。为了说明第二点,如果我改为my_method以下内容:
def my_method
my_active_record_model = MyModel.new(my_param: my_val)
my_active_record_model.save
my_active_record_model.do_something_productive
end
Run Code Online (Sandbox Code Playgroud)
然后规范的双重版本中断了,但any_instance_of版本工作得很好。
所以我的问题是,其他开发人员是如何做到这一点的?我的使用方法是否any_instance_of令人不悦?如果是这样,为什么?
我没有比您提供的两个更好的解决方案来测试这样的代码。在存根/模拟解决方案中,我将使用allow而不是expect用于调用create,因为create调用不是规范的重点,但这是一个附带问题。我同意谩骂和嘲笑是痛苦的,但这通常就是我所做的。
然而,该代码只有一点特性羡慕。提取方法可以MyModel清除气味并消除测试问题:
class MyModel < ActiveRecord::Base
def self.create_productively(attrs)
create(attrs).do_something_productive
end
end
def my_method
MyModel.create_productively(attrs)
end
# in the spec
expect(MyModel).to receive(:create_productively)
subject.my_method
Run Code Online (Sandbox Code Playgroud)
create_productively是一个模型方法,因此它可以而且应该用真实实例进行测试,并且不需要存根或模拟。
我经常注意到,需要使用 RSpec 不太常用的功能意味着我的代码需要进行一些重构。
| 归档时间: |
|
| 查看次数: |
457 次 |
| 最近记录: |