Модульное тестирование, взаимоблокировки и условия гонки
-
05-07-2019 - |
Вопрос
Любые предложения о том, как написать повторяемые модульные тесты для кода, который может быть подвержен взаимоблокировкам и условиям гонки?
Прямо сейчас я склоняюсь к тому, чтобы пропустить модульные тесты и сосредоточиться на стресс-тестах.Проблема в том, что вы можете запустить стресс-тест 5 раз и увидеть пять разных результатов.
Редактировать:Я знаю, что это, вероятно, просто мечта, но если бы существовал способ управлять отдельными потоками и заставлять их выполнять по одной инструкции за раз, тогда я мог бы чего-то добиться.
Решение
Посмотрите на TypeMock Racer (он находится в бета-версии)
изменить: на самом деле Альфа
http://www.typemock.com/Typemock_software_development_tools.html
Другие советы
Обычно можно заставить предвиденный условия гонки и взаимоблокировки с помощью таких вещей, как ManualResetEvent, чтобы перевести каждый поток в ожидаемое состояние перед его выпуском, т. е.пусть поток A установит блокировку и будет ждать сигнала...получите поток B для запроса блокировки и т.д...
Однако обычно вы можете написать такой тест для расследования предполагаемой ошибки, чтобы доказать, когда она исправлена и что она не всплывает вновь.Как правило, вы разрабатываете с учетом условий гонки (но тестируете их настолько хорошо, насколько это прагматично).
Я не думаю, что поиск условий гонки действительно относится к области юнит-тестирования. Более или менее по определению, единственный способ проверить условия гонки - это псевдослучайно. Если вы не готовы формально доказать правильность своей стратегии блокировки, вам придется провести стресс-тестирование.
Вам все еще нужно написать модульные тесты, чтобы проверить правильность алгоритмов, а не стратегию блокировки. Р>
При стресс-тестировании многопоточного кода вам нужно протестировать в условиях, когда у вас один ЦП на поток, где у вас несколько потоков, совместно использующих ЦП, и где у вас больше ЦП, чем потоков (если это возможно). р>
Вы можете написать класс блокировки, который обнаруживает потенциальные взаимоблокировки, рассматривая порядок операций блокировки. Мы делаем это, имея контекст потока, в котором регистрируются все блокировки, когда они получены (можно сделать опцию только DEBUG).
Идея состоит в том, чтобы создать граф, в котором узлы представляют блокировки, а направленный край между A и B означает «блокировка A удерживалась, когда блокировка B была получена». Дайте вашей программе работать с нормальной нагрузкой, затем проверьте циклы на графике. Цикл означает, что существует вероятность тупиковой ситуации, даже если ваш код не попал в нее.
Не могу придумать хороший автоматизированный способ, но ближе всего я подошел к написанию модульного теста, который бы «выставлял» тупик, используя точки останова в дополнение к модульному тесту. Я просто добавил несколько инструкций о том, где добавить точку останова. Прилагаются некоторые ручные усилия, но с их помощью вы всегда можете раскрыть свое расписание потоков в худшем случае.
Возможно, кто-то придумал хороший способ автоматизировать этот тип функциональности? Я мог бы представить себе автоматический запуск отладчика, разрыв одного потока в определенной строке, запуск другого потока до определенного состояния, а затем утверждение для модульного теста. Р>
Ранее я использовал искусственные задержки в коде, которые запускаются некоторыми параметрами в запросе. Например, один запрос указывает серверу задержать запись между двумя записями, а другой - выполнять их без задержки между ними. Р>
Марк Бесси пишет, что это полезно только для создания репро, а не для обнаружения проблемы.
Вы пробовали Corensic Jinx ?