我正在尝试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测试中时,self
是Class
的一个实例。我最初的想法是做这样的事情:
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"]
答案 0 :(得分:1)
要回复您的上一个问题,StringIO
会模拟文件行为。当你写/打印它时,输入光标位于你写的最后一件事之后。如果你写了一些内容并想要阅读它,你需要根据http://ruby-doc.org/stdlib-1.9.3/libdoc/stringio/rdoc/StringIO.html
rewind
,seek
等)
相反,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
的几种方法。