testing threaded code in ruby

☆樱花仙子☆ 提交于 2019-12-21 17:29:45

问题


I'm writing a delayed_job clone for DataMapper. I've got what I think is working and tested code except for the thread in the worker process. I looked to delayed_job for how to test this but there are now tests for that portion of the code. Below is the code I need to test. ideas? (I'm using rspec BTW)

def start
  say "*** Starting job worker #{@name}"
  t = Thread.new do
    loop do
      delay = Update.work_off(self) #this method well tested
      break if $exit
      sleep delay
      break if $exit
    end
    clear_locks
  end

  trap('TERM') { terminate_with t }
  trap('INT')  { terminate_with t }

  trap('USR1') do
    say "Wakeup Signal Caught"
    t.run
  end

see also this thread


回答1:


You could start the worker as a subprocess when testing, waiting for it to fully start, and then check the output / send signals to it.

I suspect you can pick up quite a few concrete testing ideas in this area from the Unicorn project.




回答2:


The best approach, I believe, is to stub the Thread.new method, and make sure that any "complicated" stuff is in it's own method which can be tested individually. Thus you would have something like this:

class Foo
    def start
        Thread.new do
            do_something
        end
    end
    def do_something
        loop do
           foo.bar(bar.foo)
        end
    end
end

Then you would test like this:

describe Foo
    it "starts thread running do_something" do
        f = Foo.new
        expect(Thread).to receive(:new).and_yield
        expect(f).to receive(:do_something)
        f.start
    end
    it "do_something loops with and calls foo.bar with bar.foo" do
        f = Foo.new
        expect(f).to receive(:loop).and_yield #for multiple yields: receive(:loop).and_yield.and_yield.and_yield... 
        expect(foo).to receive(:bar).with(bar.foo)
        f.do_something
    end
end

This way you don't have to hax around so much to get the desired result.




回答3:


Its impossible to test threads completely. Best you can do is to use mocks.

(something like) object.should_recieve(:trap).with('TERM').and yield object.start




回答4:


How about just having the thread yield right in your test.

Thread.stub(:new).and_yield
start
# assertions...


来源:https://stackoverflow.com/questions/1604802/testing-threaded-code-in-ruby

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!