Модульное тестирование параллельного программного обеспечения - что вы делаете? - PullRequest
12 голосов
/ 29 июля 2010

Поскольку программное обеспечение становится все более и более параллельным, как вы справляетесь с тестированием поведения ядра типа с вашими модульными тестами (не параллельным поведением, а только поведением ядра)?

В старые добрые времена у вас был тип, вы вызывали его, и вы проверяли, что он возвращал и / или как он называл другие вещи.

В настоящее время вы вызываете метод, и фактическая работа назначается назапустить на следующей доступной теме;вы не знаете, когда это действительно начнется и вызовет другие вещи - и более того, эти другие вещи могут быть параллельными.

Как вы справляетесь с этим?Вы абстрагируете / внедряете параллельный планировщик (например, абстрагируете библиотеку параллельных заданий и предоставляете подделку / макет в модульных тестах)?

С какими ресурсами вы столкнулись, которые вам помогли?


Редактировать

Я редактировал вопрос, чтобы подчеркнуть тестирование нормального поведения типа (игнорируя любой параллельный механизм, который используется для использования преимуществ многоядерности, например, TPL)


Ответы [ 6 ]

5 голосов
/ 29 июля 2010

Отказ от ответственности: я работаю в Corensic, небольшом стартапе в Сиэтле. У нас есть инструмент Jinx, предназначенный для обнаружения ошибок параллелизма в вашем коде. Пока мы в бета-версии, это бесплатно, так что вы можете проверить это. (http://www.corensic.com/)

Короче говоря, Jinx - это очень тонкий гипервизор, который при активации проскальзывает между процессором и операционной системой. Затем Jinx разумно берет куски выполнения и запускает симуляции различных потоков, чтобы найти ошибки. Когда мы находим конкретную синхронизацию потоков, которая может вызвать ошибку, мы делаем эту синхронизацию «реальностью» на вашей машине (например, если вы используете Visual Studio, отладчик остановится в этой точке). Затем мы указываем область в вашем коде, где была вызвана ошибка. Там нет ложных срабатываний с Jinx. Когда он обнаруживает ошибку, это определенно ошибка.

Jinx работает в Linux и Windows, а также в собственном и управляемом коде. Он не зависит от языка и платформы приложений и может работать со всеми существующими инструментами.

Если вы это проверите, отправьте нам отзыв о том, что работает, а что нет. Мы запускали Jinx в некоторых крупных проектах с открытым исходным кодом и уже наблюдаем ситуации, когда Jinx может находить ошибки в 50-100 раз быстрее, чем просто стресс-тестирование кода.

4 голосов
/ 31 июля 2010

Я рекомендую взять копию Growing Object-Oriented Software от Freeman и Pryce .Последние несколько глав очень поучительны и посвящены этой конкретной теме.Он также вводит некоторую терминологию, которая помогает закрепить нотацию для обсуждения.

Подводя итог .... Их основная идея состоит в том, чтобы разделить функциональность и аспекты одновременной работы / синхронизации .

  • Сначала протестируйте функциональную часть в единый синхронный поток, как обычный объект.
  • Как только функциональная часть будет закреплена.Вы можете перейти к параллельному аспекту.Чтобы сделать это, вам нужно подумать и придумать « наблюдаемые инварианты относительно параллелизма » для вашего объекта, например, количество должно быть равно времени вызова метода.Как только вы определили инварианты, вы можете написать стресс-тесты, которые запускают несколько потоков et.all, чтобы попытаться сломать ваши инварианты.Стресс-тесты утверждают ваши инварианты.
  • Наконец, в качестве дополнительной защиты запустите инструменты или статический анализ для поиска ошибок.

Для пассивных объектов, то есть кода, который будет вызываться из клиентовв разных потоках: ваш тест должен имитировать клиентов, запуская свои собственные потоки.Затем вам нужно будет выбрать между прослушиванием уведомлений или выборкой / опросом, чтобы синхронизировать ваши тесты с SUT.

  • Вы можете блокировать, пока не получите ожидаемое уведомление
  • Опросопределенные наблюдаемые побочные эффекты с разумным временем ожидания.
3 голосов
/ 29 июля 2010

Область юнит-тестирования для условий гонки и взаимных блокировок является относительно новой и не имеет хороших инструментов.

Мне известны два таких инструмента, как на ранней стадии альфа / бета:

Еще один вариант - попытаться написать «стресс-тест», который вызовет взаимоблокировки / условия гонки.на поверхность, создайте множественные экземпляры / потоки и запускайте их рядом.Недостатком этого подхода является то, что если тест не пройден, его будет очень сложно воспроизвести.Я предлагаю использовать логи как в тестовом, так и в рабочем коде, чтобы вы могли понять, что произошло.

1 голос
/ 29 июля 2010

Метод, который я нашел полезным, состоит в том, чтобы запускать тесты в инструменте, который обнаруживает условия гонки, такие как Intel Parallel Inspector. Тест выполняется намного медленнее, чем обычно, потому что необходимо проверять зависимости от времени, но один прогон может найти ошибки, которые в противном случае потребовали бы миллионов повторных обычных прогонов.

Я нашел это очень полезным при преобразовании существующих систем для мелкозернистого параллелизма через многоядерный.

0 голосов
/ 30 июля 2010

Учитывая, что ваш TPL будет иметь свой отдельный модульный тест, вам не нужно это проверять.

Учитывая, что я пишу два теста для каждого модуля:
1) Однопоточный модульный тест, использующий некоторую переменную среды или #define для поворота TPL, чтобы я мог проверить свой модуль на функциональную корректность.
2) Стресс-тест, который запускает модуль в режиме многопоточного развертывания. Этот тест пытается найти проблемы параллелизма и должен использовать много случайных данных.

Второй тест часто включает в себя множество модулей и, вероятно, скорее является интеграционным / системным тестом.

0 голосов
/ 29 июля 2010

Юнит-тесты действительно не должны проверять параллелизм / асинхронное поведение, вы должны использовать там mocks и убедиться, что mocks получают ожидаемый ввод.

Для интеграционных тестов я просто явно вызываю фоновую задачу, а затем проверяю ожидания.

В огурце это выглядит так:

When I press "Register"
And the email sending script is run
Then I should have an email
...