2009-09-30 16 views
17

साथ सांत्वना देने मैं जैसे कुछ इकाई परीक्षण लिख रहा हूँ निम्नलिखित:उत्पादन suppresing माणिक

def executing_a_signal 
    a_method(a_signal.new, a_model, a_helper); 
    assert_equal(new_state, a_model.state) 
end 

परीक्षण अच्छा काम है, लेकिन विधि है जो सिर्फ दावे से पहले चलाता कंसोल के लिए तर्क प्रिंट विभिन्न संदेशों पर अमल करने , मुख्य रूप से puts के माध्यम से।

क्या कंसोल पर आउटपुट को दबाने के लिए कोई त्वरित, शायद अंतर्निहित तरीका है? मुझे केवल मॉडल ऑब्जेक्ट पर विधि के अंतिम प्रभाव में दिलचस्पी है, और कंसोल को मूल रूप से साफ रखने के लिए, मैं उन सभी को फिर से लिखने या टिप्पणी करने के बिना कंसोल पर सभी आउटपुट को रोकने का एक तरीका ढूंढने की उम्मीद कर रहा था puts सिर्फ मेरे परीक्षणों के लिए बयान।

यह निश्चित रूप से एक महत्वपूर्ण मुद्दा नहीं है, लेकिन इस पर किसी भी विचार या विचार (या कामकाज) को सुनना बहुत पसंद है।

उत्तर

31

मैं टेस्ट मैचों में निम्नलिखित स्निपेट का उपयोग को पकड़ने और STDOUT

def capture_stdout(&block) 
    original_stdout = $stdout 
    $stdout = fake = StringIO.new 
    begin 
    yield 
    ensure 
    $stdout = original_stdout 
    end 
    fake.string 
end 

परीक्षण करने के लिए इस विधि के साथ, ऊपर बन जाएगा:

def executing_a_signal 
    capture_stdout { a_method(a_signal.new, a_model, a_helper) } 
    assert_equal(new_state, a_model.state) 
end 
+0

धन्यवाद, इसका शायद मतलब है कि कोई मानक अंतर्निहित तरीका नहीं है? – denchr

+0

यह – denchr

+0

सुंदर साफ समाधान, ब्रावो के रास्ते से बहुत अच्छी तरह से काम करता है! – khelll

4

वहाँ दो समाधान है: पुनः निर्देशित जहां puts को (लिखते हैं उपरोक्त @cldwalker द्वारा दिए गए समाधान), या puts विधि को स्वयं को नो-ऑप होने के लिए ओवरराइट करना। (कार्यान्वयन स्पष्ट होना चाहिए: module Kernel; def puts(*args) end end)।

हालांकि, इस मामले में, वास्तव में सबसे अच्छा समाधान "आपके परीक्षणों को सुनना" होगा। क्योंकि, कई बार जब परीक्षण करने के लिए कुछ अजीब होता है, तो आपके परीक्षण वास्तव में आपको यह बताने की कोशिश कर रहे हैं कि आपके डिजाइन में कुछ गड़बड़ है। इस मामले में, मैं एकल उत्तरदायित्व सिद्धांत का उल्लंघन करता हूं: कंसोल को लिखने के तरीके के बारे में जानने के लिए मॉडल ऑब्जेक्ट को बिल्ली की आवश्यकता क्यों होती है? इसकी ज़िम्मेदारी एक डोमेन अवधारणा का प्रतिनिधित्व कर रही है, लॉगिंग नहीं! लॉगर ऑब्जेक्ट्स यही है!

तो, एक वैकल्पिक समाधान मॉडल ऑब्जेक्ट को लॉगर ऑब्जेक्ट पर लॉगिंग करने की ज़िम्मेदारी सौंपना होगा, और उचित ऑब्जेक्ट के साथ मॉडल ऑब्जेक्ट को इंजेक्ट करने के लिए निर्भरता इंजेक्शन का उपयोग करना होगा। इस तरह, आप परीक्षण के लिए नकली लॉगर इंजेक्ट कर सकते हैं।यहाँ एक उदाहरण है:

#!/usr/bin/env ruby 

class SomeModel 
    def initialize(logger=Kernel) @logger = logger end 
    def some_method_that_logs; @logger.puts 'bla' end 
end 

require 'test/unit' 
require 'stringio' 
class TestQuietLogging < Test::Unit::TestCase 
    def setup; @old_stdout, $> = $>, (@fake_logdest = StringIO.new) end 
    def teardown; $> = @old_stdout end 

    def test_that_default_logging_is_still_noisy 
    SomeModel.new.some_method_that_logs 

    assert_equal "bla\n", @fake_logdest.string 
    end 

    def test_that_logging_can_be_made_quiet 
    fake_logger = Object.new 
    def fake_logger.puts *args; end 

    SomeModel.new(fake_logger).some_method_that_logs 

    assert_equal '', @fake_logdest.string 
    end 
end 

कम से कम, मॉडल वस्तु, IO उद्देश्य यह है कि यह एक तर्क के रूप करने के लिए पेड़ों की कटाई लेना चाहिए ताकि आप बस परीक्षण के लिए इसे में StringIO.new इंजेक्षन कर सकते हैं:

#!/usr/bin/env ruby 

class SomeModel 
    def initialize(logdest=$>) @logdest = logdest end 
    def some_method_that_logs; @logdest.puts 'bla' end 
end 

require 'test/unit' 
require 'stringio' 
class TestQuietLogging < Test::Unit::TestCase 
    def setup; @old_stdout, $> = $>, (@fake_logdest = StringIO.new) end 
    def teardown; $> = @old_stdout end 

    def test_that_default_logging_is_still_noisy 
    SomeModel.new.some_method_that_logs 

    assert_equal "bla\n", @fake_logdest.string 
    end 

    def test_that_logging_can_be_made_quiet 
    fake_logdest = (@fake_logdest = StringIO.new) 

    SomeModel.new(fake_logdest).some_method_that_logs 

    assert_equal '', @fake_logdest.string 
    assert_equal "bla\n", fake_logdest.string 
    end 
end 

आप अभी भी सिर्फ puts whatever कहने के लिए अपने मॉडल में सक्षम होना चाहते हैं या आपको डर है कि कोई लकड़हारा वस्तु पर puts फोन भूल भी सकते हैं, तो आप प्रदान कर सकते हैं अपने खुद के (निजी) डालता विधि:

class SomeModel 
    def initialize(logdest=$>) @logdest = logdest end 
    def some_method_that_logs; puts 'bla' end 
    private 
    def puts(*args) @logdest.puts *args end 
end 
1

reopen '/dev/null'

एक अन्य विकल्प के साथ /dev/null के लिए पुनः निर्देशित करने के लिए है:

STDOUT.reopen('/dev/null', 'w') 
STDERR.reopen('/dev/null', 'w') 

इस तकनीक stdlib (स्रोत टॉगल) के WEBrick::Daemon पर प्रयोग किया जाता है।

StringIO.new से अधिक कुशल होने का लाभ है क्योंकि यह StringIO पर stdout स्टोर नहीं करता है, लेकिन यह कम पोर्टेबल है।

2

एक थोड़ा क्लीनर @ cldwalker के समाधान पर ले:

def silenced 
    $stdout = StringIO.new 

    yield 
ensure 
    $stdout = STDOUT 
end 

silenced do 
    something_that_prints 
end 
0

मैं बस अपना .rb फ़ाइल की शुरुआत में नीचे दिए गए कोड का इस्तेमाल किया .. तो यह सब सांत्वना प्रिंट बयान को निष्क्रिय ..

def puts(*args) end