在测试类和测试类之间共享状态

时间:2013-11-06 14:50:55

标签: ruby rspec

我正在尝试RSpec。 由于我不喜欢模拟,我想使​​用StringIO对象来模拟控制台打印。

所以,我想测试Logger类将Welcome写入控制台。为此,我的想法是覆盖spec文件中puts内使用的Logger方法,这样在其他地方使用Logger时实际上没有任何变化。

以下是一些代码:

describe Logger do
    Logger.class_eval do
        def puts(*args)
            ???.puts(*args)
        end
    end

    it 'says "Welcome"' do
end

这样做,我需要在StringIO类和测试类之间共享一些Logger对象(现在会出现问号的位置)。

我发现当我在RSpec测试中时,selfClass的一个实例。我最初的想法是做这样的事情:

Class.class_eval do
    attr_accessor :my_io
    @my_io = StringIO.new
end

然后将???替换为Class.my_io

当我这样做的时候,我头上响起了一千个铃声,告诉我这不是一个干净的方式。

我该怎么办?

PS:我仍然没有得到这个:

a = StringIO.new
a.print('a')
a.string # => "a"
a.read # => "" ??? WHY???
a.readlines # => [] ???

仍然:StringIO.new('hello').readlines # => ["hello"]

3 个答案:

答案 0 :(得分:1)

要回复您的上一个问题,StringIO会模拟文件行为。当你写/打印它时,输入光标位于你写的最后一件事之后。如果你写了一些内容并想要阅读它,你需要根据http://ruby-doc.org/stdlib-1.9.3/libdoc/stringio/rdoc/StringIO.html

重新定位自己(例如rewindseek等)

相反,StringIO.new('hello')建立hello作为字符串的初始内容,同时保留在0的位置。无论如何,string方法只返回内容,独立于位置。

答案 1 :(得分:1)

目前尚不清楚为什么RSpec中的测试双重机制存在问题。

尽管如此,您的共享方法的方法仍然有效:

  • self是RSpec describe中的匿名类并不是真正相关的事实
  • 您可以定义自己的类和关联的类方法,而不是使用Class的实例方法,而不是如下所示:

    类Foo   def self.bar(arg)     看跌期权(ARG)   结束 端

    描述“共享stringio”做

    Foo.class_eval做     def self.puts(* args)       MyStringIO.my_io.print(*参数)     结束   端

    类MyStringIO     @my_io = StringIO.new     def self.my_io; @my_io;结束   端

    它'说'欢迎''做     Foo.bar( “欢迎”)     expect(MyStringIO.my_io.string).to eql“Welcome”   端

答案 2 :(得分:0)

Logger已经允许在construction上指定输出设备,因此您可以轻松直接传递StringIO,而无需重新定义任何内容:

require 'logger'

describe Logger do

  let(:my_io) { StringIO.new }
  let(:log)   { Logger.new(my_io) }

  it 'says welcome' do
    log.error('Welcome')
    expect(my_io.string).to include('ERROR -- : Welcome')
  end
end

正如其他海报所提到的,目前还不清楚你是打算测试Logger还是某些使用它的代码。对于后者,请将injecting记录器考虑到客户端代码中。

this SO question的答案还显示了在客户端之间共享公共Logger的几种方法。