Rspec: как проверить файловые операции и содержимое файла
В моем приложении у меня есть такой код:
File.open "filename", "w" do |file|
file.write("text")
end
Я хочу проверить этот код через rspec. Какова лучшая практика для этого?
5 ответов
Я бы предложил использовать StringIO
для этого и убедитесь, что ваше SUT принимает поток для записи вместо имени файла. Таким образом, можно использовать разные файлы или выходные данные (более пригодные для повторного использования), включая строку IO (подходит для тестирования)
Так в вашем тестовом коде (при условии, что ваш экземпляр SUT sutObject
и сериализатор назван writeStuffTo
:
testIO = StringIO.new
sutObject.writeStuffTo testIO
testIO.string.should == "Hello, world!"
Строка ввода-вывода ведет себя как открытый файл. Так что, если код уже может работать с объектом File, он будет работать с StringIO.
Для очень простого ввода-вывода вы можете просто смоделировать File. Итак, учитывая:
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.
Вот как смоделировать File (с помощью 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
Вы можете использовать fakefs.
Это заглушает файловую систему и создает файлы в памяти
Вы проверяете с
File.exists? "filename"
если файл был создан.
Вы также можете просто прочитать это с
File.open
и запустить ожидание на его содержание.
Для кого-то вроде меня, которому нужно изменить несколько файлов в нескольких каталогах (например, генератор для 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)