我想知道这个解决方案是否得到了ruby中mocking对象的社区认可。如果没有,请描述为什么,以及如何改进代码设计或测试。
假设我有以下代码。
lib/config_loader.rb
class ConfigLoader
HOME_DIR = '~/my/home_dir'.freeze
...
def load(path)
path = File.expand_path(path)
if File.exist?(path)
File.read(path)
else
File.read(HOME_DIR)
end
end
end
在测试时,我实际上不希望在变量中定义的path
下创建任何东西,所以我只想模拟的这种行为
spec/lib/config_loader_spec.rb
RSpec.describe ConfigLoader do
describe '.load' do
subject { described.class.new.load(path) }
let(:path) { 'path/that/should/exist' }
context 'when path' do
before do
allow(File).to receive(:exist?).with(path).and_return(true)
allow(File).to receive(:read).with(path).and_return('my content')
end
it { expect { subject }.to_not raise_error { Errno::ENOENT }
end
end
end
也许我应该做一些File
类的class_double
。我不确定我提供的方式,所以我需要一些信息如何在通用/最佳实践方式中做到这一点
测试驱动/行为驱动开发/设计的基本原则之一是不要嘲笑你不拥有的东西(在Steve Freeman和Nat Pryce的《成长的面向对象软件,以测试为指导》一书中创造(。
你的例子违反了这个原则:你没有File
,所以你不应该嘲笑它
相反,您可以创建自己的抽象,用于与文件系统交互,而文件系统只有您实际需要的功能。然后您可以创建这个抽象的两个实现:一个使用Ruby的File
类,另一个不做任何事情的mock。如果你想变得新奇,你甚至可以在内存中创建一个模拟文件系统的文件系统。
当然,您现在已经解决了这个问题:您的文件抽象实现中有未经测试的代码。然而,理想情况下,该代码应该是";几乎";不重要的很明显,您仍然可以对文件抽象实现进行集成测试,也可以对使用真实实现而不是mock或模拟的ConfigLoader
进行集成测试。
如果你感兴趣,这里有一些进一步的阅读:
- 那不是你的,埃里克·史密斯(第八光(
- 不要嘲笑你没有的东西,Testdouble.com
- TDD:只有你自己的mock类型,Mark Needham(Neo4J(
- 不要嘲笑你不拥有的东西,马克西姆·伊万诺夫
- 不要嘲笑你不拥有的东西,马特的代码洞穴
- 不要嘲笑你没有的东西:现实世界的场景,Giovanni Pinto
- 不要嘲笑你不拥有的类型,David Tchepak