如何rspec线程代码?

时间:2014-03-01 08:48:15

标签: ruby multithreading rspec



从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测试它的方法。有没有关于测试线程代码的有效文档?任何可以帮助我的宝石? 我有点受阻,提前谢谢

1 个答案:

答案 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

等...