Подтвердить что ты не робот

Единичное тестирование в режиме реального времени/параллельное программное обеспечение

Возможный дубликат:
Как мне unit test код с резьбой?

Классическое модульное тестирование в основном просто помещает x в и ожидает y out и автоматизирует этот процесс. Так что это хорошо для тестирования всего, что не связано с временем. Но тогда большинство нетривиальных ошибок, с которыми я столкнулся, имели какое-то отношение к времени. Потоки повреждают данные друг друга или вызывают взаимоблокировки. Недетерминированное поведение происходит - за один миллион. Жесткий материал.

Есть ли что-нибудь полезное для "модульного тестирования" частей многопоточных параллельных систем? Как работают такие тесты? Разве вам не нужно долгое время изучать предмет таких тестов и каким-то умным образом изменять среду, чтобы стать разумно уверенным в том, что она работает правильно?

4b9b3361

Ответ 1

Большая часть работы, которую я делаю в эти дни, включает многопоточные и/или распределенные системы. Большинство ошибок включают ошибки "случится раньше", когда разработчик предполагает (ошибочно), что событие A всегда будет происходить до события B. Но каждые 1000000-й раз, когда программа запускается, событие B происходит первым, и это вызывает непредсказуемое поведение.

Кроме того, на самом деле нет никаких хороших инструментов для обнаружения проблем с синхронизацией или даже повреждения данных, вызванных условиями гонки. Такие инструменты, как Helgrind и drd из инструментария Valgrind, отлично подходят для тривиальных программ, но они не очень полезны при диагностике больших сложных систем. Во-первых, они довольно часто сообщают о ложных срабатываниях (особенно Helgrind). С другой стороны, трудно обнаружить определенные ошибки во время работы под Helgrind/drd просто потому, что программы под управлением Helgrind работают почти на 1000 раз медленнее, и вам часто нужно запускать программу довольно долго, чтобы даже воспроизвести состояние гонки. Кроме того, поскольку запуск под Helgrind полностью изменяет время выполнения программы, может возникнуть возможность воспроизвести определенную проблему времени. Это проблема с тонкими проблемами времени; они почти Гейзенбергиан в том смысле, что изменение программы для выявления проблем времени может скрыть исходную проблему.

Печальный факт заключается в том, что человеческая раса еще недостаточно подготовлена ​​для решения сложного параллельного программного обеспечения. К сожалению, нет простого способа провести его тестирование. Особенно для распределенных систем вы должны тщательно планировать свою программу, используя Lamport происходит перед диаграммами, чтобы помочь вам определить необходимый порядок событий в вашей программе. Но, в конечном счете, вы не можете избавиться от тестирования модулей грубой силы со случайными переменными входами. Это также помогает варьировать частоту переключения контекста потока во время вашего модульного теста, например, запускает другой фоновый процесс, который просто занимает циклы процессора. Кроме того, если у вас есть доступ к кластеру, вы можете запускать несколько модульных тестов параллельно, что позволяет быстрее обнаруживать ошибки и экономить много времени.

Ответ 2

Если вы можете запускать тесты под Linux, valgrind включает в себя инструмент helgrind, который предназначен для обнаружения условий гонки и возможных взаимоблокировок в программах, которые используют Pthreads; вы можете получить некоторую выгоду от запуска вашего многопоточного кода в соответствии с этим, поскольку он сообщит о потенциальных ошибках, даже если они фактически не произошли в этом конкретном тестовом прогоне.

Ответ 3

Я никогда не слышал ничего, что может.

Я предполагаю, что если кто-то должен был его разработать, он должен был бы точно контролировать выполнение потоков и выполнять все возможные комбинации степпинга потоков.

Звучит как основная задача, не говоря уже о математических комбинациях для потоков нетривиального размера, когда есть несколько или более из них...

Хотя, быстрый поиск stackoverflow... Модульное тестирование многопоточного приложения?

Ответ 4

Если тестируемая система достаточно проста, вы можете довольно хорошо управлять concurrency, блокируя операции во внешних макетных системах. Эта блокировка может быть выполнена, например, путем ожидания запуска какой-либо другой операции. Если вы можете контролировать все внешние вызовы, это может работать довольно хорошо, реализуя различные последовательности блокировки. Я пробовал это, и он обнаруживает ошибки уровня блокировки достаточно хорошо, если вы хорошо знаете возможные проблемные последовательности. И по сравнению со многими другими тестами concurrency он довольно детерминирован. Однако этот подход не слишком хорошо определяет условия гонки с низким уровнем. Обычно я просто нахожусь для тестирования нагрузки, чтобы найти их, но я хочу, чтобы это не было точно модульным тестированием.

Я видел эти concurrency рамки тестирования для .net, я бы предположил, что это единственный вопрос времени, прежде чем кто-то пишет его для Java (надеюсь).

И не забыть хорошее старое чтение кода. Один из лучших способов найти ошибки concurrency - это просто прочитать код еще раз, давая ему полную концентрацию.

Ответ 5

Возможно, ответ заключается в том, что вы не должны. В параллельных системах не всегда может быть один правильный детерминированный ответ.

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

Ответ 6

Awaitility - полезная среда, когда вам нужно иметь дело с асинхронностью в ваших тестах. Это позволяет подождать, пока некоторое состояние в вашей системе будет обновлено. Например:

await().untilCall( to(myService).myMethod(), equalTo(3) );

или

await().until( fieldIn(myObject).ofType(int.class), greaterThan(1));

Он также поддерживает Scala и Groovy.