测试方法在Ruby中调用super

时间:2011-03-08 12:14:35

标签: ruby unit-testing testunit

我有一个测试库来帮助测试日志记录:

require 'stringio'

module RedirectIo
  def setup
    $stderr = @stderr = StringIO.new
    $stdin = @stdin = StringIO.new
    $stdout = @stdout = StringIO.new
    super
  end

  def teardown
    $stderr = STDERR
    $stdin = STDIN
    $stdout = STDOUT
    super
  end
end

它意味着像这样使用:

require 'lib/redirect_io'

class FooTest < Test::Unit::TestCase
  include RedirectIo

  def test_logging
    msg = 'bar'
    Foo.new.log msg
    assert_match /^#{TIMESTAMP_REGEX} #{msg}$/, @stdout.string, 'log message'
  end
end

当然,我对我的测试库进行了单元测试。 :)

require 'lib/redirect_io'

class RedirectIoTest < Test::Unit::TestCase
  def test_setup_and_teardown_are_mixed_in
    %W{setup teardown}.each do |method|
      assert_not_equal self.class, self.class.new(__method__).method(method).owner, "owner of method #{method}"
    end

    self.class.class_eval { include RedirectIo }
    %W{setup teardown}.each do |method|
      assert_equal RedirectIo, self.class.new(__method__).method(method).owner, "owner of method #{method}"
        end
  end

  def test_std_streams_captured
    %W{STDERR STDIN STDOUT}.each do |stream_name|
      assert_equal eval(stream_name), self.class.new(__method__).instance_eval("$#{stream_name.downcase}"), stream_name
    end

    self.class.class_eval { include RedirectIo }

    setup
    %W{STDERR STDIN STDOUT}.each do |stream_name|
      assert_not_equal eval(stream_name), self.class.new(__method__).instance_eval("$#{stream_name.downcase}"),
          stream_name
    end

    teardown
    %W{STDERR STDIN STDOUT}.each do |stream_name|
      assert_equal eval(stream_name), self.class.new(__method__).instance_eval("$#{stream_name.downcase}"), stream_name
    end
  end
end

我无法弄清楚如何测试 RedirectIo.setup 拆解调用super。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

我想出了一种方法,它实际上使测试代码更加清晰!

require 'lib/redirect_io'

class RedirectIoTest < Test::Unit::TestCase
  class RedirectIoTestSubjectSuper < Test::Unit::TestCase
    def setup
      @setup = true
    end
    def teardown
      @teardown = true
    end
  end

  class RedirectIoTestSubject < RedirectIoTestSubjectSuper
    include RedirectIo
    def test_fake; end
  end

  def test_setup_and_teardown_are_mixed_in
    %W{setup teardown}.each do |method|
      assert_not_equal RedirectIoTestSubject, self.method(method).owner, "owner of method #{method}"
    end

    %W{setup teardown}.each do |method|
      assert_equal RedirectIo, RedirectIoTestSubject.new(:test_fake).method(method).owner, "owner of method #{method}"
    end
  end

  def test_std_streams_captured
    obj = RedirectIoTestSubject.new(:test_fake)
    $stderr = STDERR
    $stdin = STDIN
    $stdout = STDOUT

    obj.setup
    %W{STDERR STDIN STDOUT}.each do |stream_name|
      assert_not_equal eval(stream_name), eval("$#{stream_name.downcase}"), stream_name
    end

    obj.teardown
    %W{STDERR STDIN STDOUT}.each do |stream_name|
      assert_equal eval(stream_name), eval("$#{stream_name.downcase}"), stream_name
    end
  end

  def test_setup_and_teardown_call_super
    obj = RedirectIoTestSubject.new(:test_fake)
    obj.setup
    assert obj.instance_eval{@setup}, 'super called?'
    obj.teardown
    assert obj.instance_eval{@teardown}, 'super called?'
  end
end