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

Ruby 在测试类和测试类之间共享状态,ruby,rspec,Ruby,Rspec,我正在用RSpec做实验。 因为我不喜欢mock,所以我想使用StringIO对象模拟控制台打印 因此,我想测试Logger类是否将Welcome写入控制台。为此,我的想法是从spec文件中重写Logger中使用的put方法,以便在其他地方使用Logger时不会发生任何实际更改 下面是一些代码: describe Logger do Logger.class_eval do def puts(*args) ???.puts(*args)

我正在用RSpec做实验。 因为我不喜欢mock,所以我想使用
StringIO
对象模拟控制台打印

因此,我想测试
Logger
类是否将
Welcome
写入控制台。为此,我的想法是从spec文件中重写
Logger
中使用的
put
方法,以便在其他地方使用
Logger
时不会发生任何实际更改

下面是一些代码:

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

    it 'says "Welcome"' do
end
通过这种方式,我需要在
Logger
类和测试类之间共享一些
StringIO
对象(现在问号所在的位置)

我发现在RSpec测试中,
self
类的一个实例。我最初的想法是这样做:

Class.class_eval do
    attr_accessor :my_io
    @my_io = StringIO.new
end
然后将
替换为
Class.my\u io

当我这么做的时候,无数的钟声在我脑海中响起,告诉我这不是一个干净的方法

我能做什么

附言:我还是不明白:

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

仍然:
StringIO.new('hello')。readlines#=>[“hello”]
为了响应您最后的问题,
StringIO
模拟文件行为。写入/打印时,输入光标位于上次写入的内容之后。如果您写了一些东西并想读回,您需要根据


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

不清楚为什么RSpec中的test double机制存在问题

也就是说,您共享方法的方法是有效的,尽管:

  • 事实上,
    self
    是RSpec的
    descripe
    中的一个匿名类,这一点并不重要
  • 您可以定义自己的类和关联的类方法,并将其“共享”,而不是使用
    类的实例方法,如下所示:

    福班 def自调节杆(arg) puts(arg) 结束 结束

    请描述“共享stringio”是什么

    Foo.class\u eval do 定义自置位(*args) MyStringIO.my_io.print(*args) 结束 结束

    MyStringIO类 @my_io=StringIO.new def self.my_io@我的爱;结束 结束

    它“说”欢迎“做什么 富吧(“欢迎”) expect(MyStringIO.my_io.string).to eql“Welcome” 结束

    结束


记录器
已经允许在上指定输出设备,因此您可以轻松地直接传入您的
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
还是使用它的一些代码。在后者的情况下,将记录器考虑到客户端代码中。


的答案还显示了在客户端之间共享通用
记录器的几种方法。

这非常适合:)。非常感谢。很抱歉,我不知道
Logger
是一个Ruby模块:)。我的意思是表示要测试的泛型类(不幸的是,我也将其命名为
Logger
)。所以重点是测试一个泛型类。PS:无论如何,当您创建
@my_io
并在
class_eval
中引用它时,
@my_io
不是引用了
记录器
类变量吗?(假设
self
指向
Logger
)。当然,你是对的。对不起,那件事。我的编辑窗口和我正在测试的内容之间存在断开连接。;-)无论如何,我更新了答案,并考虑到您不打算引用Ruby的日志。有一个误解,请参阅对Peter答案的评论。啊,我明白了。实际上,我建议使用与stdlib记录器相同的设计:允许注入混凝土输出设备(在施工期间或通过设置器)。这使得测试非常容易(只需传入一个
StringIO
),而且将
Logger
与实际的日志记录目标分离-所有这些都不需要太多麻烦,也没有黑客攻击。