在我的应用中,我有这样的代码:
File.open "filename", "w" do |file|
file.write("text")
end
我想通过rspec测试这段代码。这样做的最佳做法是什么?
答案 0 :(得分:56)
我建议您使用StringIO
并确保您的SUT接受要写入的流而不是文件名。这样,可以使用不同的文件或输出(更可重用),包括字符串IO(适合测试)
因此在您的测试代码中(假设您的SUT实例为sutObject
且序列化程序名为writeStuffTo
:
testIO = StringIO.new
sutObject.writeStuffTo testIO
testIO.string.should == "Hello, world!"
字符串IO的行为类似于打开的文件。因此,如果代码已经可以使用File对象,它将适用于StringIO。
答案 1 :(得分:46)
对于非常简单的i / o,你可以模拟文件。所以,给定:
def foo
File.open "filename", "w" do |file|
file.write("text")
end
end
然后:
describe "foo" do
it "should create 'filename' and put 'text' in it" do
file = mock('file')
File.should_receive(:open).with("filename", "w").and_yield(file)
file.should_receive(:write).with("text")
foo
end
end
然而,这种方法在存在多个读/写时会失败:简单的重构不会改变文件的最终状态会导致测试中断。在这种情况下(可能在任何情况下)你应该更喜欢@Danny Staple的答案。
答案 2 :(得分:18)
这是如何模拟文件(使用rspec 3.4),因此您可以写入缓冲区并稍后检查其内容:
it 'How to mock File.open for write with rspec 3.4' do
@buffer = StringIO.new()
@filename = "somefile.txt"
@content = "the content fo the file"
allow(File).to receive(:open).with(@filename,'w').and_yield( @buffer )
# call the function that writes to the file
File.open(@filename, 'w') {|f| f.write(@content)}
# reading the buffer and checking its content.
expect(@buffer.string).to eq(@content)
end
答案 3 :(得分:17)
答案 4 :(得分:0)
对于像我这样需要修改多个目录中的多个文件的人(例如Rails的生成器),我使用临时文件夹。
Dir.mktmpdir do |dir|
Dir.chdir(dir) do
# Generate a clean Rails folder
Rails::Generators::AppGenerator.start ['foo', '--skip-bundle']
File.open(File.join(dir, 'foo.txt'), 'w') {|f| f.write("write your stuff here") }
expect(File.exist?(File.join(dir, 'foo.txt'))).to eq(true)