web-dev-qa-db-fra.com

Test de la sortie STDOUT dans Rspec

J'essaie de construire une spécification pour cette déclaration. C'est facile avec des 'put'

print "'#{@file}' doesn't exist: Create Empty File (y/n)?"
41
user2292710

RSpec 3.0+

RSpec 3.0 ajout d'un nouveau output matcher à cet effet:

expect { my_method }.to output("my message").to_stdout
expect { my_method }.to output("my error").to_stderr

Minitest

Minitest a également quelque chose appelé capture_io :

out, err = capture_io do
  my_method
end

assert_equals "my message", out
assert_equals "my error", err

RSpec <3.0 (et autres)

Pour RSpec <3.0 et d'autres frameworks, vous pouvez utiliser l'aide suivante. Cela vous permettra de capturer tout ce qui est envoyé à stdout et stderr, respectivement:

require 'stringio'

def capture_stdout(&blk)
  old = $stdout
  $stdout = fake = StringIO.new
  blk.call
  fake.string
ensure
  $stdout = old
end

def capture_stderr(&blk)
  old = $stderr
  $stderr = fake = StringIO.new
  blk.call
  fake.string
ensure
  $stderr = old
end

Maintenant, quand vous avez une méthode qui devrait imprimer quelque chose sur la console

def my_method
  # ...
  print "my message"
end

vous pouvez écrire une spécification comme celle-ci:

it 'should print "my message"' do
  printed = capture_stdout do
    my_method # do your actual method call
  end

  printed.should eq("my message")
end
79
Patrick Oscity

Si votre objectif est seulement de pouvoir tester cette méthode, je le ferais comme ceci:

class Executable
  def initialize(outstream, instream, file)
    @outstream, @instream, @file = outstream, instream, file
  end

  def Prompt_create_file
    @outstream.print "'#{@file}' doesn't exist: Create Empty File (y/n)?"
  end
end


# when executing for real, you would do something like
# Executable.new $stdout, $stdin, ARGV[0]

# when testing, you would do
describe 'Executable' do
  before { @input = '' }
  let(:instream)   { StringIO.new @input }
  let(:outstream)  { StringIO.new }
  let(:filename)   { File.expand_path '../testfile', __FILE__ }
  let(:executable) { Executable.new outstream, instream, filename }

  specify 'Prompt_create_file prompts the user to create a new file' do
    executable.Prompt_create_file
    outstream.string.should include "Create Empty File (y/n)"
  end
end

Cependant, je tiens à souligner que je ne testerais pas directement une méthode comme celle-ci. Au lieu de cela, je testerais le code qui l'utilise. Hier, je parlais avec un apprenti potentiel, et il faisait quelque chose de très similaire, alors je me suis assis avec lui, et nous avons réimplémenté une partie de la classe, vous pouvez voir que ici .

J'ai aussi un blog qui parle de ce genre de chose.

3
Joshua Cheek