Dans mon application, j'ai un tel code:
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?
Je suggère d'utiliser StringIO
pour cela et de vous assurer que votre SUT accepte un flux dans lequel écrire au lieu d'un nom de fichier. De cette façon, différents fichiers ou sorties peuvent être utilisés (plus réutilisables), y compris la chaîne IO (utile pour les tests).
Donc, dans votre code de test (en supposant que votre instance SUT est sutObject
et que le sérialiseur s'appelle writeStuffTo
:
testIO = StringIO.new
sutObject.writeStuffTo testIO
testIO.string.should == "Hello, world!"
La chaîne IO se comporte comme un fichier ouvert. Donc, si le code peut déjà fonctionner avec un objet File, il fonctionnera avec StringIO.
Pour des entrées/sorties très simples, vous pouvez simplement vous moquer de File. Donc, étant donné:
def foo
File.open "filename", "w" do |file|
file.write("text")
end
end
puis:
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 échoue en présence de plusieurs lectures/écritures: de simples refactorisations qui ne modifient 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.
Voici comment simuler un fichier (avec rspec 3.4), afin que vous puissiez é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
Vous pouvez utiliser fakefs .
Il arrête 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 lancez des attentes sur son contenu.
Pour quelqu'un comme moi qui doit modifier plusieurs fichiers dans plusieurs répertoires (par exemple, un générateur pour Rails), j'utilise un dossier temporaire.
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)