Тестирование критичного по времени кода - PullRequest
1 голос
/ 17 ноября 2009

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

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

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

Ответы [ 2 ]

2 голосов
/ 17 ноября 2009

Из вашего репозитория 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

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

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 немного неприятно, но я сделал предположение, что пульсатор будет записывать пары символ / обратное пространство атомарно. Если это не так, вы сможете вставить escape-последовательность \ b в строку iterated_chars и полностью удалить последнее назначение.

1 голос
/ 17 ноября 2009

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

Только операционная система реального времени может дать вам такую ​​точность. Вы можете Предположим, что Thread.Sleep имеет точность около 20 мс, так что вы могли бы, в теории спать до желаемого времени - Фактическое время составляет около 20 мс, а затем вращаться в течение 20 мс, но вам придется тратить эти 20 мс. И даже это не гарантирует, что вы станете настоящим результаты по времени, планировщик может просто вынуть свою ветку только тогда, когда это было о выполнении СООТВЕТСТВУЮЩЕЙ части (только после вращения)

Проблема не в Ruby (возможно, я не специалист по Ruby), проблема в возможностях вашей операционной системы в реальном времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...