2013-03-15 13 views
29

Ich teste die Klasse, die auf der Konsole einige Nachrichten (mit Puts, P-Warnungen und usw.). Ich frage mich nur, ob es eine Möglichkeit gibt, diese Ausgabe während RSpec Tests zu unterdrücken?Konsolenausgabe bei RSpec-Tests unterdrücken

+1

Architektonisch ist es besser, wenn Sie eine Protokollierungsbibliothek verwenden oder die print-Anweisungen irgendwie einkapseln, so dass Sie den Druckvorgang von einer globalen Konfiguration aus umschalten können. Es wäre nicht schwer zu suchen und ersetzen mit sed alle 'print',' p', etc. mit 'Your :: Logger.warn' oder etwas. – alexanderbird

Antwort

32

ich unterdrücken puts Ausgabe in meinen Klassen von $stout in eine Textdatei umleiten. Auf diese Weise, wenn ich die Ausgabe aus irgendeinem Grund sehen muss, ist es da, aber es verschleiert meine Testergebnisse nicht.

#spec_helper.rb 
RSpec.configure do |config| 
    config.before(:all, &:silence_output) 
    config.after(:all, &:enable_output) 
end 

public 
# Redirects stderr and stout to /dev/null.txt 
def silence_output 
    # Store the original stderr and stdout in order to restore them later 
    @original_stderr = $stderr 
    @original_stdout = $stdout 

    # Redirect stderr and stdout 
    $stderr = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w') 
    $stdout = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w') 
end 

# Replace stderr and stdout so anything else is output correctly 
def enable_output 
    $stderr = @original_stderr 
    $stdout = @original_stdout 
    @original_stderr = nil 
    @original_stdout = nil 
end 

EDIT:

Als Reaktion auf den Kommentar von @MyronMarston, es wäre wahrscheinlich klüger, nur die Methoden in before und after als Blöcke direkt einfügen.

#spec_helper.rb 
RSpec.configure do |config| 
    original_stderr = $stderr 
    original_stdout = $stdout 
    config.before(:all) do 
    # Redirect stderr and stdout 
    $stderr = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w') 
    $stdout = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w') 
    end 
    config.after(:all) do 
    $stderr = original_stderr 
    $stdout = original_stdout 
    end 
end 

Es sieht ein wenig sauberer und hält Methoden aus der main. Beachten Sie außerdem, dass Sie, wenn Sie Ruby 2.0 verwenden, __dir__ anstelle von File.dirname(__FILE__) verwenden können.

EDIT2

Es sollte auch erwähnt werden, dass Sie auf true os /dev/null unter Verwendung File::NULL weiterleiten kann, wie es in Ruby v 1.9.3 eingeführt wurde. (Jruby 1.7)

Dann wird der Code-Schnipsel aussehen wird, wie folgend:

#spec_helper.rb 
RSpec.configure do |config| 
    original_stderr = $stderr 
    original_stdout = $stdout 
    config.before(:all) do 
    # Redirect stderr and stdout 
    $stderr = File.open(File::NULL, "w") 
    $stdout = File.open(File::NULL, "w") 
    end 
    config.after(:all) do 
    $stderr = original_stderr 
    $stdout = original_stdout 
    end 
end 
+0

Vielen Dank. – demas

+3

Dies ist eine ziemlich gute Lösung, aber bedenken Sie, dass es 'silence_output' und' enable_output' für jedes Objekt im System hinzufügt. Ich denke, es ist in kleinen, einmaligen Skripten in Ordnung, aber ansonsten vermeide ich es, Methoden auf 'main' zu definieren. –

+1

@MyronMarston Sie haben Recht. Obwohl es keine Probleme verursachen kann, da es nur für RSpec-Tests gedacht ist, wäre es schlauer, sie von "main" fernzuhalten. Ich fügte meine Antwort hinzu, um das zu reflektieren. –

25

Versuchen Sie Stubbing-Methoden, die die Ausgabe in einem vor-Block, z.

before do 
    IO.any_instance.stub(:puts) # globally 
    YourClass.any_instance.stub(:puts) # or for just one class 
end 

Dies ist explizit, damit Sie nichts verpassen, was Sie nicht verpassen möchten. Wenn Sie nicht über einen beliebigen Ausgang und dem oben beschriebenen Verfahren ist es egal nicht funktioniert, können Sie immer die IO-Objekt Stummel selbst:

before do 
    $stdout.stub(:write) # and/or $stderr if needed 
end 
+0

Danke, es funktioniert, aber ich bevorzuge Charles Methode :) – demas

+0

so einfach zu stub out '$ stdout' auf die Tests, die ich weiß, werde schreiben und ich will sie nicht, danke :) – sevenseacat

10

Wenn Sie eine Ausgabe für einen einzelnen Test zu unterdrücken wollen, gibt es eine prägnante Art und Weise:

it "should do something with printing" do 
    silence_stream(STDOUT) do 
    foo.print.should be_true 
    end 
end 

Möglicherweise möchten Sie STDOUT zu STDERR ändern, wenn Ihr Test einen Fehler ausgibt.

+3

Ich wollte feststellen, dass [silence_stream] (http://apidock.com/rails/Kernel/silence_stream) ein Teil von [activesupport] (http://apidock.com/rails/ActiveSupport) ist. –

+3

[silence_stream ist jetzt veraltet] (http://www.rubydoc.info/gems/activesupport/4.2.0/Kernel: silence_stream) – dgmstuart

13

Eine Rspec3.0 Version wäre => in spec_helper.rb

RSpec.configure do |c| 
    c.before { allow($stdout).to receive(:puts) } 
end 

als before(:each)

handeln aber: jeder Standard ist, so dass keine Notwendigkeit, es explizit

+2

Stubbing ': schreibe' statt '' puts' arbeitete für mich. –

+0

'allow ($ stdout) .zu empfangen (: puts)' (oder ': write') sollte die akzeptierte Antwort sein –

7

schreiben Getestet mit rspec-core (~> 3.4.0)

In beschreiben Block Sie

# spec_helper.rb 
def suppress_log_output 
    allow(STDOUT).to receive(:puts) # this disables puts 
    logger = double('Logger').as_null_object 
    allow(Logger).to receive(:new).and_return(logger) 
end 

# some_class_spec.rb 
RSpec.describe SomeClass do 
    before do 
    suppress_log_output 
    end 
end 

diese Weise können Sie den Vorteil haben, tun könnte Protokollausgabe für spezifische Tests von Makeln. Beachten Sie, dass nicht RSPec-Warnungen oder Nachrichten von RSPEC unterdrücken wird.

Eine weitere Möglichkeit Warnungen deaktivieren von Edelsteinen kommen:

config.warnings = false hinzufügen

spec_helper Wenn Sie error, info, or warn nur bestimmte Logger Methoden zu unterdrücken wollen Sie

allow_any_instance_of(Logger).to receive(:warn).and_return(nil)

tun könnten Warnungen deaktivieren, die vom rspec gem stammen

allow(RSpec::Support).to receive(:warning_notifier).and_return(nil)

aber dies wird im Allgemeinen abgeraten, weil es eine Möglichkeit ist, Sie wissen zu lassen, dass Sie in Ihren Tests etwas übel riechen.

3

aktualisiert Antwort für Rails 5, in einer einmaligen Situation:

before do 
    RSpec::Mocks.with_temporary_scope do 
    allow(STDOUT).to receive(:puts) 
    end 
end 

Sie können dies in einem Verfahren in spec_helper machen, wenn Sie diese viel tun werde.