49 votes

RSpec : comment tester les opérations sur les fichiers et le contenu des fichiers

Dans mon application, j'ai le code suivant :

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

Je veux tester ce code via RSpec. Quelles sont les meilleures pratiques pour le faire ?

0 votes

@Wayne Je me demande comment vous allez procéder avec testunit Voir [cette question][1][1] : stackoverflow.com/questions/11619884/

65voto

Danny Staple Points 1725

Je suggère d'utiliser StringIO pour cela et s'assurer que votre SUT accepte un flux vers lequel écrire au lieu d'un nom de fichier. De cette façon, différents fichiers ou sorties peuvent être utilisés (plus réutilisable), y compris la chaîne IO (bon pour les tests)

Ainsi, dans votre code de test (en supposant que votre instance SUT est sutObject et le sérialiseur est nommé writeStuffTo :

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

String IO se comporte comme un fichier ouvert. Donc si le code peut déjà fonctionner avec un objet File, il fonctionnera avec StringIO.

1 votes

C'était une excellente réponse. J'aimerais pouvoir vous mettre en avant plus d'une fois.

2 votes

Bonne réponse, je sais que ce n'était pas demandé mais cela aurait été parfait si elle avait inclus l'exemple du partenaire "lu" également.

1 votes

Comment modifier le code pour utiliser String.IO ? Il semble que le code résultant sera beaucoup plus laid, juste pour que les tests soient plus faciles ?

52voto

Wayne Conrad Points 31052

Pour des entrées/sorties très simples, vous pouvez simplement simuler File. Donc, donné :

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

alors :

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

Cependant, cette approche tombe à plat en présence de lectures/écritures multiples : de simples refactorings qui ne changent pas l'état final du fichier peuvent provoquer la rupture du test. Dans ce cas (et éventuellement dans tous les cas), vous devriez préférer la réponse de @Danny Staple.

22voto

Eduardo Santana Points 551

Voici comment simuler un fichier (avec rspec 3.4), afin de pouvoir écrire dans un tampon et vérifier son contenu ultérieurement :

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

19voto

mehowte Points 278

Vous pouvez utiliser fauxfs .

Il supprime le système de fichiers et crée des fichiers en mémoire.

Vous vérifiez avec

File.exists? "filename" 

si le fichier a été créé.

Vous pouvez aussi simplement le lire avec

File.open 

et de lancer une espérance sur son contenu.

1 votes

Notez que FakeFS échoue avec Rspec (tant Rspec 2 que Rspec 3) - github.com/fakefs/fakefs/issues/215

3voto

lulalala Points 3895

Pour quelqu'un comme moi qui a besoin de modifier plusieurs fichiers dans plusieurs répertoires (par exemple le générateur pour Rails), j'utilise le dossier temp.

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)
  end
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X