从rspec开始,我在尝试测试线程代码时遇到了困难。
这是一个简单的代码创建,我做了它因为我需要一个具有超时功能的队列
require "thread"
class TimeoutQueue
def initialize
@lock = Mutex.new
@items = []
@new_item = ConditionVariable.new
end
def push(obj)
@lock.synchronize do
@items.push(obj)
@new_item.signal
end
end
def pop(timeout = :never)
timeout += Time.now unless timeout == :never
@lock.synchronize do
loop do
time_left = timeout == :never ? nil : timeout - Time.now
if @items.empty? and time_left.to_f >= 0
@new_item.wait(@lock, time_left)
end
return @items.shift unless @items.empty?
next if timeout == :never or timeout > Time.now
return nil
end
end
end
alias_method :<<, :push
end
但我找不到使用rspec测试它的方法。有没有关于测试线程代码的有效文档?任何可以帮助我的宝石? 我有点受阻,提前谢谢
答案 0 :(得分:3)
当单元测试我们不希望任何非确定性行为影响我们的测试时,所以在测试线程时我们不应该并行运行任何东西。
相反,我们应该隔离我们的代码,模拟我们想要测试的案例,方法是@lock
,@new_item
,甚至Time.now
(为了更具可读性,我冒昧地想象你也有attr_reader :lock, :new_item
):
it 'should signal after push' do
allow(subject.lock).to receive(:synchronize).and_yield
expect(subject.new_item).to receive(:signal)
subject.push('object')
expect(subject.items).to include('object')
end
it 'should time out if taken to long to enter synchronize loop' do
@now = Time.now
allow(Time).to receive(:now).and_return(@now, @now + 10.seconds)
allow(subject.items).to receive(:empty?).and_return true
allow(subject.lock).to receive(:synchronize).and_yield
expect(subject.new_item).to_not receive(:wait)
expect(subject.pop(5.seconds)).to be_nil
end
等...