тестирование многопоточного кода в ruby
-
05-07-2019 - |
Вопрос
Я пишу клон delayed_job
для DataMapper. У меня есть то, что я думаю, работает и протестировал код, за исключением потока в рабочем процессе. Я посмотрел в delayed_job
, как это проверить, но сейчас есть тесты для этой части кода. Ниже приведен код, который мне нужно проверить. идеи? (Я использую 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
см. также эту тему
Решение
Вы можете запустить рабочий процесс как подпроцесс при тестировании, дождаться его полного запуска, а затем проверить сигналы вывода / отправки на него. Р>
Я подозреваю, что вы можете найти довольно много конкретных идей для тестирования в этой области из проекта Unicorn . р>
Другие советы
На мой взгляд, лучший подход - это заглушить метод Thread.new
и убедиться, что любой " сложный " материал по-своему, который можно проверить индивидуально. Таким образом, у вас будет что-то вроде этого:
class Foo
def start
Thread.new do
do_something
end
end
def do_something
loop do
foo.bar(bar.foo)
end
end
end
Тогда вы бы протестировали так:
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
Таким образом, вам не нужно так много раздувать, чтобы получить желаемый результат.
Невозможно полностью протестировать потоки. Лучшее, что вы можете сделать, это использовать насмешки.
(что-то вроде) object.should_recieve (: trap) .with ('TERM'). и yield object.start р>
Как насчет того, чтобы поток получился прямо в вашем тесте?
Thread.stub(:new).and_yield
start
# assertions...