简体   繁体   中英

Rspec should wait for threads to finish

There is an error running a spec listed below. It does not wait for threads to complete and unstub a migrate method resulting that one of threads hits a real method.
Noticed it only happens with rails loaded, without them it is working correctly or just finish faster...

Spec:

it "should not allow infinit recursion" do
  runner.stub(total_records: 4)
  runner.stub(:fetch_records_batch).and_return([:one, :two])
  runner.should_receive(:migrate).at_most(100).times
  expect { runner.run }.to raise_error(Exception, /Migration fall into recursion/)
end

it "should pass"
  1.should eq 1
end

Extracted piece of code:

class Runner
  def migrate(record)
    raise NotImplementedError
  end

  def run
     while have_records?(records = fetch_records_batch)
       threads = []
       records.each do |record|
         threads << Thread.new(record) do |thread_record|
           begin
             result = migrate(thread_record)
           rescue RuntimeError => exception
             register_event :record_migration_error, thread_record, exception
           end
         end
         recursion_preventer
      end
      threads.each(&:join)
    end
  end

  def recursion_preventer
    @counter ||= 0
    @counter += 1
    raise Exception, "Migration fall into recursion. Check logs." if @counter > (total_records * 1.1).round + 10
  end
end

You can always mock the Thread class to simply not start threads, but run the code instead, which I find is much less intrusive than rewriting tests the way you suggest.

Add this to your test-class:

describe MyClass do
  before(:each) do
    allow(Thread).to receive(:new).and_yield
  end
  #Your normal unaltered tests under here
end

The pitfall of this method is that you won't experience race conditions so the code can still include bugs such as "thread a and thread b writes to the same variable at the same time, causing issues". You should also consider dead lock scenarios, as code that relies on other threads to finish something will most likely lock up with this approach.

通过添加ensure块并调用threads.each(&:join)并在records.each之后移动recursion_preventer来解决

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM