模拟ruby核心类的正确方法

模拟ruby核心类的正确方法,ruby,rspec,rspec-mocks,Ruby,Rspec,Rspec Mocks,我想知道这个解决方案是否通过在ruby中模拟对象得到了社区的认可。如果没有,请说明原因,以及如何改进代码设计或测试 假设我有以下代码 lib/config\u loader.rb 类配置加载器 HOME\u DIR='~/my/HOME\u DIR'。冻结 ... def加载(路径) 路径=文件。展开路径(路径) 如果文件.exist?(路径) File.read(路径) 其他的 File.read(主目录) 结束 结束 结束 在测试时,我实际上不希望在变量中定义的path下创建任何内容,所以

我想知道这个解决方案是否通过在ruby中模拟对象得到了社区的认可。如果没有,请说明原因,以及如何改进代码设计或测试

假设我有以下代码

lib/config\u loader.rb

类配置加载器
HOME\u DIR='~/my/HOME\u DIR'。冻结
...
def加载(路径)
路径=文件。展开路径(路径)
如果文件.exist?(路径)
File.read(路径)
其他的
File.read(主目录)
结束
结束
结束
在测试时,我实际上不希望在变量中定义的
path
下创建任何内容,所以我只想模拟这种行为

spec/lib/config\u loader\u spec.rb

RSpec.description ConfigLoader do
描述“.load”做什么
主题{descripted.class.new.load(path)}
let(:path){'path/that/should/exist'}
上下文“当路径”执行时
在做之前
允许(文件)。接收(:存在?)。使用(路径)。并返回(真)
允许(文件)。接收(:读取)。使用(路径)。和返回('my content')
结束
它{expect{subject}.to{u不引发错误{Errno::enoint}
结束
结束
结束
也许我应该做一些
class\u double
文件
类。我不确定我提供的方式,所以我需要一些信息如何以通用/最佳实践的方式来做这件事

测试驱动/行为驱动开发/设计的基本原则之一是不要模仿你不拥有的东西(在书中创造)

你的例子违反了这个原则:你没有
文件
,因此你不应该嘲笑它

相反,您可以创建自己的抽象,以便与文件系统交互,而文件系统只具有您实际需要的功能。然后您可以创建此抽象的两个实现:一个使用Ruby的
文件
类,另一个不做任何事的模拟实现。如果您想喜欢,甚至可以在在内存中模拟文件系统的

当然,您现在已经解决了这个问题:您现在的文件抽象实现中有未经测试的代码很明显,您仍然可以对文件抽象实现进行集成测试,也可以对
ConfigLoader
进行集成测试,该测试使用真实实现而不是模拟或模拟

如果您感兴趣,这里有一些进一步的阅读:

测试驱动/行为驱动开发/设计的基本原则之一是不要嘲笑你不拥有的东西(在书中创造)

你的例子违反了这个原则:你没有
文件
,因此你不应该嘲笑它

相反,您可以创建自己的抽象,以便与文件系统交互,而文件系统只具有您实际需要的功能。然后您可以创建此抽象的两个实现:一个使用Ruby的
文件
类,另一个不做任何事的模拟实现。如果您想喜欢,甚至可以在在内存中模拟文件系统的

当然,您现在已经解决了这个问题:您现在的文件抽象实现中有未经测试的代码很明显,您仍然可以对文件抽象实现进行集成测试,也可以对
ConfigLoader
进行集成测试,该测试使用真实实现而不是模拟或模拟

如果您感兴趣,这里有一些进一步的阅读:

退房退房