2010-11-01 6 views
39

w moim app mam taki kod:RSpec: jak sprawdzić operacje na plikach i złożyć zawartości

File.open "filename", "w" do |file| 
    file.write("text") 
end 

Chcę przetestować ten kod poprzez RSpec. Jakie są najlepsze praktyki w tym zakresie?

+0

@Wayne Zastanawiam się, w jaki sposób postępować z testunit patrz [to pytanie] [1] [1]: http://stackoverflow.com/questions/11619884/ testunit-how-to-test-file-operations-and-file-content – netbe

Odpowiedz

53

Proponuję użyć do tego celu StringIO i upewnić się, że SUT akceptuje strumień do zapisu zamiast nazwy pliku. W ten sposób różne pliki lub wyjścia mogą być wykorzystane (więcej wielokrotnego użytku), w tym ciąg IO (dobry do testowania)

to w kodzie testowym (zakładając, że instancja SUT jest sutObject i serializer nazwie writeStuffTo:

testIO = StringIO.new 
sutObject.writeStuffTo testIO 
testIO.string.should == "Hello, world!" 

String IO zachowuje się jak otwartego pliku. Więc jeśli kod już może pracować z obiektem pliku, to będzie działać z StringIO.

+0

To była doskonała odpowiedź. Chciałbym móc cię głosować więcej niż raz. – Jazzepi

+1

Dobra odpowiedź, wiem, że nie została zadana, ale byłoby idealnie, gdyby zawierała również przykład "przeczytania" partnera. –

+1

Jak zmodyfikować kod, aby użyć String.IO? Wydaje się, że wynikowy kod będzie znacznie brzydszy, tak więc testowanie jest łatwiejsze? –

44

przypadku bardzo prosty I/o, można po prostu mock plików. Tak więc, biorąc pod uwagę :

def foo 
    File.open "filename", "w" do |file| 
    file.write("text") 
    end 
end 

następnie:

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 

Jednak takie podejście spada płasko w obecności wielu odczytuje/zapisuje: proste refaktoryzacji, które nie zmieniają stan końcowy pliku może spowodować test złamać. W takim przypadku (i ewentualnie w każdym przypadku) powinieneś wybrać odpowiedź @Danny Staple.

17

Można użyć fakefs.

To odcinki plików i tworzy pliki w pamięci

sprawdzeniu z

File.exists? "filename" 

jeśli plik został utworzony.

Można też po prostu czytać z

File.open 

i uruchomić oczekiwanie na jego zawartość.

+1

Należy pamiętać, że FakeFS nie działa z Rspec (zarówno Rspec 2, jak i Rspec 3) - https://github.com/fakefs/fakefs/issues/215 –

10

ten sposób mock File (z rspec 3.4), więc można pisać do bufora i sprawdzić jego zawartość później:

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 
0

Dla kogoś takiego jak ja, który trzeba zmodyfikować kilka plików w różnych katalogach (np. generator dla Railsów), używam folderu tymczasowego.

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)