In meiner App habe ich solchen Code:
File.open "filename", "w" do |file|
file.write("text")
end
Ich möchte diesen Code über rspec testen. Was ist die beste Vorgehensweise, um dies zu tun?
Ich würde vorschlagen, StringIO
zu verwenden und sicherzustellen, dass Ihr SUT anstelle eines Dateinamens einen Stream zum Schreiben akzeptiert. Auf diese Weise können verschiedene Dateien oder Ausgaben verwendet werden (wiederverwendbar), einschließlich der Zeichenfolge IO (zum Testen geeignet).
Also in Ihrem Testcode (vorausgesetzt, Ihre SUT-Instanz ist sutObject
und der Serializer heißt writeStuffTo
:
testIO = StringIO.new
sutObject.writeStuffTo testIO
testIO.string.should == "Hello, world!"
String IO verhält sich wie eine geöffnete Datei. Wenn der Code bereits mit einem File-Objekt arbeiten kann, funktioniert es auch mit StringIO.
Für sehr einfache E/A können Sie einfach nur File nachahmen. Also gegeben:
def foo
File.open "filename", "w" do |file|
file.write("text")
end
end
dann:
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
Dieser Ansatz ist jedoch bei mehreren Lese-/Schreibvorgängen unangemessen: Einfache Umgestaltungen, die den Endzustand der Datei nicht ändern, können dazu führen, dass der Test bricht. In diesem Fall (und möglicherweise in jedem Fall) sollten Sie die Antwort von @Danny Staple vorziehen.
So spiegeln Sie File (mit rspec 3.4), sodass Sie später in einen Puffer schreiben und dessen Inhalt überprüfen können:
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
Sie können fakefs verwenden.
Er stubpt das Dateisystem und erstellt Dateien im Speicher
Sie prüfen mit
File.exists? "filename"
wenn Datei erstellt wurde.
Sie können es auch einfach mit lesen
File.open
und Erwartung des Inhalts.
Für jemanden wie mich, der mehrere Dateien in mehreren Verzeichnissen ändern muss (z. B. Generator für Rails), verwende ich den temporären Ordner.
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)