wake-up-neo.com

Rspec: So testen Sie Dateioperationen und Dateiinhalte

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?

39
petRUShka

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.

55
Danny Staple

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.

46
Wayne Conrad

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
18
Eduardo Santana

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. 

17
mehowte

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)
0
lulalala