2009-11-17 5 views
1

Я написал функцию для своей библиотеки Rubikon, которая отображает throbber (вращение —, как вы могли видеть в других консольных приложениях), пока работает какой-либо другой код.Критический код времени тестирования

Чтобы проверить эту функцию, я фиксирую вывод тромбона в StringIO и сравниваю его с ожидаемым значением. Поскольку показания throbber отображаются только до тех пор, пока выполняется другой код, содержимое IO становится длиннее, когда код работает дольше. В моих тестах я делаю простой sleep 1 и должен иметь постоянную задержку в 1 секунду. Это работает большую часть времени, но иногда (по-видимому, из-за внешних факторов, таких как тяжелая нагрузка на CPU) он терпит неудачу, потому что код не работает в течение 1 секунды, а немного больше, так что throbber печатает несколько дополнительных персонажи.

Мой вопрос: есть ли возможность проверить такие критические моменты времени в Ruby?

ответ

2

Из вашего репозитория GitHub, я нашел этот тест для класса Throbber:

should 'work correctly' do 
    ostream = StringIO.new 
    thread = Thread.new { sleep 1 } 
    throbber = Throbber.new(ostream, thread) 
    thread.join 
    throbber.join 
    assert_equal " \b-\b\\\b|\b/\b", ostream.string 
end 

Я предполагаю, что через Throbber перебирает ['-', '\', '|', '/'], реверса перед каждой записи, один раз в секунду. Рассмотрим следующий тест:

should 'work correctly' do 
    ostream = StringIO.new 
    started_at = Time.now 
    ended_at = nil 
    thread = Thread.new { sleep 1; ended_at = Time.now } 
    throbber = Throbber.new(ostream, thread) 
    thread.join 
    throbber.join 
    duration = ended_at - started_at 
    iterated_chars = " -\\|/" 
    expected = "" 
    if duration >= 1 
    # After n seconds we should have n copies of " -\\|/", excluding \b for now 
    expected << iterated_chars * duration.to_i 
    end 
    # Next append the characters we'd get from working for fractions of a second: 
    remainder = duration - duration.to_i 
    expected << iterated_chars[0..((iterated_chars.length*remainder).to_i)] if remainder > 0.0 
    expected = expected.split('').join("\b") + "\b" 
    assert_equal expected, ostream.string 
end 

Последнее назначение expected немного неприятно, но я сделал предположение, что Throbber бы писать пары символов/BackSpace атомарно. Если это неверно, вы должны будете вставить escape-последовательность \ b в строку iterated_chars и полностью удалить последнее назначение.

+0

Звучит неплохо, я проверю это. – Koraktor

1

Этот вопрос похож (я думаю, Altough я не совсем уверен) в this one:

только в режиме реального времени операционная система может дать вам такую ​​точность. Вы можете предположить Thread.Sleep имеет точность около 20 мс, так что вы могли бы, в теории спать до желаемого времени - фактическое время составляет около 20 мс, а затем спина в течение 20 мс, но вы должны будете тратить эти 20 мс. И даже то, что не гарантирует, что вы получите реальные результаты времени, планировщик может просто взять нить из только тогда, когда это было собирается выполнить соответствующую часть (сразу после отжима)

Проблема не в том, что rubby (возможно, я не эксперт в ruby), проблема в операционных системах реального времени.

+0

Я знаю, что я не могу ожидать поведения в реальном времени от операционной системы, отличной от реального времени, и особенно от языка сценариев, такого как Ruby. Мой вопрос заключается не в устранении задержек, чтобы получить поведение в реальном времени, я просто хочу исключить побочные эффекты в модульных тестах. – Koraktor