До сих пор я избегал кошмара, в котором тестируется многопоточный код, поскольку он кажется слишком большим минным полем. Я хотел бы спросить, как люди пошли на тестирование кода, который опирается на потоки для успешного выполнения, или просто как люди пошли на тестирование тех видов проблем, которые проявляются только тогда, когда два потока взаимодействуют определенным образом?
Сегодня это кажется действительно ключевой проблемой для программистов, было бы полезно объединить наши знания по этому вопросу.
Ответы:
Смотри, нет простого способа сделать это. Я работаю над проектом, который по своей сути многопоточный. События поступают из операционной системы, и я должен обрабатывать их одновременно.
Самый простой способ справиться с тестированием сложного многопоточного кода приложения: если он слишком сложен для тестирования, вы делаете это неправильно. Если у вас есть один экземпляр с несколькими потоками, действующими на него, и вы не можете проверить ситуации, когда эти потоки пересекаются друг с другом, то ваш дизайн необходимо переделать. Это так же просто и так сложно.
Существует много способов программирования многопоточности, позволяющих избежать одновременного выполнения потоков через экземпляры. Самое простое - сделать все ваши объекты неизменяемыми. Конечно, это обычно не возможно. Таким образом, вы должны определить те места в вашем проекте, где потоки взаимодействуют с одним и тем же экземпляром, и уменьшить количество этих мест. Делая это, вы изолируете несколько классов, где на самом деле происходит многопоточность, что снижает общую сложность тестирования вашей системы.
Но вы должны понимать, что даже делая это, вы все равно не можете проверить каждую ситуацию, когда два потока наступают друг на друга. Для этого вам нужно будет одновременно запустить два потока в одном и том же тесте, а затем точно контролировать, какие строки они выполняют в данный момент. Лучшее, что вы можете сделать, это смоделировать эту ситуацию. Но это может потребовать от вас написания кода специально для тестирования, и это в лучшем случае полшага к настоящему решению.
Вероятно, лучший способ проверить код на наличие потоков - это статический анализ кода. Если ваш многопоточный код не следует конечному набору потоковых шаблонов, возможно, у вас проблема. Я считаю, что Code Analysis в VS содержит некоторые знания о многопоточности, но, вероятно, не так много.
Посмотрите, как обстоят дела в настоящее время (и, вероятно, наступит хорошее время), лучший способ протестировать многопоточные приложения - максимально снизить сложность многопоточного кода. Минимизируйте области, в которых взаимодействуют потоки, тестируйте как можно лучше и используйте анализ кода для выявления опасных областей.
источник
Это было время, когда этот вопрос был опубликован, но он до сих пор не ответил ...
Ответ kleolb02 хороший. Я постараюсь вдаваться в подробности.
Есть способ, который я практикую для кода C #. Для модульных тестов вы должны иметь возможность программировать воспроизводимые тесты, что является самой большой проблемой в многопоточном коде. Так что мой ответ направлен на то, чтобы заставить асинхронный код использовать тестовую систему, которая работает синхронно .
Это идея из книги Джерарда Месардоса « Тестовые шаблоны xUnit », которая называется «Смиренный объект» (стр. 695): вы должны отделить основной логический код и все, что пахнет асинхронным кодом друг от друга. Это привело бы к классу для базовой логики, который работает синхронно .
Это позволяет вам синхронно тестировать основной логический код . Вы имеете абсолютный контроль над временем вызовов, которые вы делаете в основной логике, и, таким образом, можете выполнять воспроизводимые тесты. И это ваша выгода от разделения базовой логики и асинхронной логики.
Эта базовая логика должна быть обернута другим классом, который отвечает за асинхронный прием вызовов базовой логики и делегирует эти вызовы базовой логике. Рабочий код получит доступ к основной логике только через этот класс. Поскольку этот класс должен только делегировать вызовы, это очень «тупой» класс без особой логики. Таким образом, вы можете сохранить свои модульные тесты для этого асинхронного рабочего класса как минимум.
Все, что выше этого (тестирование взаимодействия между классами), является тестированием компонентов. Также в этом случае вы должны иметь абсолютный контроль над временем, если вы придерживаетесь шаблона «Humble Object».
источник
Трудный действительно! В моих (C ++) модульных тестах я разбил это на несколько категорий в соответствии с используемым шаблоном параллелизма:
Модульные тесты для классов, которые работают в одном потоке и не поддерживают потоки - просто, тестируйте как обычно.
Модульные тесты для объектов Monitor (тех, которые выполняют синхронизированные методы в потоке контроля вызывающих), которые предоставляют синхронизированный общедоступный API - создают несколько фиктивных потоков, которые осуществляют API. Построить сценарии, которые осуществляют внутренние условия пассивного объекта. Включите один более продолжительный тест, который в основном выбивает его из нескольких потоков в течение длительного периода времени. Я знаю, что это ненаучно, но это вселяет уверенность.
Модульные тесты для активных объектов (те, которые инкапсулируют свой собственный поток или потоки управления) - аналогично # 2 выше с вариациями в зависимости от дизайна класса. Публичный API может быть блокирующим или неблокирующим, вызывающие абоненты могут получать фьючерсы, данные могут поступать в очереди или должны быть исключены из очереди. Здесь возможно множество комбинаций; белая коробка прочь По-прежнему требуется несколько фиктивных потоков для выполнения вызовов тестируемого объекта.
Как в сторону:
На внутреннем обучении разработчиков, которое я делаю, я преподаю Столпы Параллелизма и эти два паттерна как основную структуру для размышления и разложения проблем параллелизма. Очевидно, есть более продвинутые концепции, но я обнаружил, что этот набор основ помогает не допустить появления инженеров. Это также приводит к тому, что код будет более тестируемым, как описано выше.
источник
В последние годы я сталкивался с этой проблемой несколько раз, когда писал код обработки потоков для нескольких проектов. Я даю поздний ответ, потому что большинство других ответов, хотя и предоставляют альтернативы, на самом деле не отвечают на вопрос о тестировании. Мой ответ адресован случаям, когда нет альтернативы многопоточному коду; Я рассматриваю вопросы проектирования кода для полноты, но также обсуждаю модульное тестирование.
Написание тестируемого многопоточного кода
Первое, что нужно сделать, это отделить ваш код обработки производственных потоков от всего кода, который выполняет фактическую обработку данных. Таким образом, обработка данных может быть протестирована как однопоточный код, и единственное, что делает многопоточный код, - это координирует потоки.
Второе, что нужно помнить, это то, что ошибки в многопоточном коде вероятностны; ошибки, которые проявляются реже всего, - это ошибки, которые проникнут в производство, их будет трудно воспроизвести даже в процессе производства, и, следовательно, они вызовут самые большие проблемы. По этой причине стандартный подход к кодированию - быстро написать код, а затем отладить его, пока он не заработает, - плохая идея для многопоточного кода; это приведет к коду, в котором исправлены простые ошибки, а опасные ошибки все еще существуют.
Вместо этого, при написании многопоточного кода, вы должны писать код с позиции, которую вы собираетесь избегать, во-первых, избегая написания ошибок. Если вы правильно удалили код обработки данных, код обработки потоков должен быть достаточно маленьким - предпочтительно несколько строк, в худшем случае несколько десятков строк - чтобы у вас была возможность написать его без написания ошибки и, конечно же, без написания множества ошибок. Если вы понимаете многопоточность, не торопитесь, и будьте осторожны.
Написание модульных тестов для многопоточного кода
Как только многопоточный код написан настолько тщательно, насколько это возможно, все еще стоит написать тесты для этого кода. Основной целью тестов является не столько тестирование на наличие ошибок состояния гонки, зависящих от времени, - их невозможно повторить, но скорее тестирование того, что ваша стратегия блокировки для предотвращения таких ошибок позволяет нескольким потокам взаимодействовать по назначению ,
Чтобы правильно проверить правильность поведения блокировки, тест должен запустить несколько потоков. Чтобы сделать тест повторяемым, мы хотим, чтобы взаимодействия между потоками происходили в предсказуемом порядке. Мы не хотим внешнюю синхронизацию потоков в тесте, потому что это замаскирует ошибки, которые могут произойти в производственном процессе, когда потоки не синхронизированы извне. Это оставляет использование временных задержек для синхронизации потоков, что является техникой, которую я успешно использовал всякий раз, когда мне приходилось писать тесты многопоточного кода.
Если задержки слишком малы, то тест становится хрупким, потому что незначительные различия во времени - скажем, между разными машинами, на которых могут выполняться тесты - могут привести к отключению синхронизации и провалу теста. Обычно я начинаю с задержек, которые приводят к сбоям теста, увеличивают задержки, чтобы тест надежно проходил на моей машине для разработки, а затем удваивают задержки сверх этого, чтобы у теста был хороший шанс пройти на других машинах. Это означает, что тест займет макроскопическое количество времени, хотя, по моему опыту, тщательная разработка теста может ограничить это время не более чем дюжиной секунд. Поскольку в вашем приложении не должно быть много мест, требующих кода координации потоков, это должно быть приемлемо для вашего набора тестов.
Наконец, отслеживайте количество ошибок, обнаруженных вашим тестом. Если ваш тест покрывает 80% кода, можно ожидать, что он поймает около 80% ваших ошибок. Если ваш тест хорошо спроектирован, но не обнаружил ошибок, есть разумный шанс, что у вас не будет дополнительных ошибок, которые будут отображаться только в рабочей среде. Если тест обнаружит одну или две ошибки, вам все равно может повезти. Помимо этого, и вы можете рассмотреть возможность тщательного анализа или даже полного переписывания кода обработки потоков, поскольку вполне вероятно, что код все еще содержит скрытые ошибки, которые будет очень трудно найти, пока код не будет запущен, и очень трудно исправить тогда.
источник
У меня также были серьезные проблемы с тестированием многопоточного кода. Тогда я нашел действительно классное решение в «Тестовых шаблонах xUnit» Джерарда Месароса. Образец, который он описывает, называется скромным объектом .
В основном он описывает, как вы можете извлечь логику в отдельный, легко тестируемый компонент, который отделен от его среды. После проверки этой логики вы можете проверить сложное поведение (многопоточность, асинхронное выполнение и т. Д.)
источник
Есть несколько хороших инструментов вокруг. Вот краткое изложение некоторых из Java.
Некоторые хорошие инструменты статического анализа включают FindBugs (дает несколько полезных советов), JLint , Java Pathfinder (JPF & JPF2) и Bogor .
MultithreadedTC - это неплохой инструмент динамического анализа (встроенный в JUnit), в котором вам нужно создавать свои собственные тестовые случаи.
ConTest от IBM Research - это интересно. Он обрабатывает ваш код, вставляя все виды поведения, изменяющего потоки (например, сон и выход), чтобы попытаться случайно обнаружить ошибки.
ВРАЩЕНИЕ - это действительно классный инструмент для моделирования ваших Java (и других) компонентов, но вам нужно иметь некоторую полезную среду. Трудно использовать как есть, но чрезвычайно мощный, если вы знаете, как его использовать. Многие инструменты используют SPIN под капотом.
MultithreadedTC, вероятно, является наиболее распространенным, но некоторые из перечисленных выше инструментов статического анализа, безусловно, заслуживают внимания.
источник
Awaitility также может быть полезен для написания детерминированных модульных тестов. Это позволяет вам ждать, пока какое-то состояние в вашей системе не будет обновлено. Например:
или
Он также имеет поддержку Scala и Groovy.
источник
Еще один способ (своего рода) тестирования многопоточного кода и очень сложных систем в целом - это Fuzz Testing . Это не здорово, и он не найдет все, но он, вероятно, будет полезен и прост в выполнении.
Quote:
источник
Я сделал много этого, и да, это отстой.
Несколько советов:
throwable
поле и зарегистрируйте егоtearDown
(см. Листинг 1). Если вы поймали плохое исключение в другом потоке, просто назначьте его для throwable.AtomicBoolean
в ваших тестах. Это потокобезопасно, и вам часто понадобится конечный ссылочный тип для хранения значений из классов обратного вызова и тому подобное. Смотрите пример в листинге 3.@Test(timeout=60*1000)
), так как тесты параллелизма могут иногда зависать вечно, если они не работают.Листинг 1:
Листинг 2:
Листинг 3:
источник
Как уже говорилось, тестирование МТ-кода на правильность является довольно сложной задачей. В итоге все сводится к тому, чтобы в вашем коде не было неправильно синхронизированных гонок данных. Проблема в том, что существует бесконечно много возможностей выполнения потоков (чередования), над которыми у вас нет особого контроля ( хотя обязательно прочитайте эту статью). В простых сценариях можно было бы реально доказать правильность, рассуждая, но обычно это не так. Особенно, если вы хотите избежать / минимизировать синхронизацию и не использовать самый очевидный / самый простой вариант синхронизации.
Подход, которым я придерживаюсь, заключается в написании тестового кода с высокой степенью параллелизма, что может привести к потенциально необнаруженным скачкам данных. А потом я какое-то время запускал эти тесты :) Однажды я наткнулся на беседу, в которой какой-то ученый демонстрирует инструмент, который это делает (случайным образом разрабатывает тесты из спецификаций, а затем дико, параллельно выполняет их, проверяя определенные инварианты). быть сломанным).
Кстати, я думаю, что этот аспект тестирования кода MT здесь не упоминался: выявляйте инварианты кода, которые вы можете проверить случайным образом. К сожалению, найти эти инварианты тоже довольно сложно. Кроме того, они могут не удерживаться все время во время выполнения, поэтому вы должны найти / применить точки выполнения, где вы можете ожидать, что они будут истинными. Приведение выполнения кода в такое состояние также является сложной проблемой (и может привести к проблемам с параллелизмом. Вот, черт возьми, это сложно!
Некоторые интересные ссылки для чтения:
источник
У Пита Гудлиффа есть серия статей о модульном тестировании многопоточного кода.
Это сложно. Я выбрал более простой путь и постарался не допустить, чтобы многопоточный код был абстрагирован от реального теста. Пит упоминает, что то, как я это делаю, неверно, но я либо получил правильное разделение, либо мне просто повезло.
источник
Для Java посмотрите главу 12 JCIP . Есть несколько конкретных примеров написания детерминированных многопоточных модульных тестов, чтобы хотя бы проверить правильность и инварианты параллельного кода.
«Доказывать» безопасность потоков с помощью модульных тестов гораздо сложнее. Я считаю, что это лучше подходит для автоматизированного интеграционного тестирования на различных платформах / конфигурациях.
источник
Мне нравится писать два или более тестовых метода для выполнения в параллельных потоках, и каждый из них делает вызовы в тестируемый объект. Я использовал вызовы Sleep () для координации порядка вызовов из разных потоков, но это не совсем надежно. Это также намного медленнее, потому что вы должны спать достаточно долго, чтобы время работало.
Я нашел многопоточную библиотеку Java TC из той же группы, в которой была написана FindBugs. Это позволяет вам определять порядок событий без использования Sleep (), и это надежно. Я еще не пробовал.
Основным ограничением этого подхода является то, что он позволяет вам тестировать только те сценарии, которые, по вашему мнению, могут вызвать проблемы. Как уже говорили другие, вам действительно нужно разделить ваш многопоточный код на небольшое количество простых классов, чтобы иметь надежду на тщательное их тестирование.
После того, как вы тщательно протестировали сценарии, которые, как вы ожидаете, вызовут проблемы, ненаучный тест, который на некоторое время бросает кучу одновременных запросов в класс, является хорошим способом поиска неожиданных проблем.
Обновление: я немного поиграл с многопоточной Java-библиотекой TC, и она хорошо работает. Я также перенес некоторые из его функций в версию .NET, которую я называю TickingTest .
источник
Я выполняю модульные тесты резьбовых компонентов так же, как и любые юнит-тесты, то есть с инверсией систем управления и изоляции. Я разрабатываю на .Net-арене, и из коробки очень трудно (даже скажу почти невозможно) многопоточность (среди прочего) полностью изолировать.
Поэтому я написал обертки, которые выглядят примерно так (упрощенно):
Оттуда я могу легко внедрить IThreadingManager в мои компоненты и использовать выбранную мной среду изоляции, чтобы заставить поток работать так, как я ожидаю во время теста.
До сих пор это отлично работало для меня, и я использую тот же подход для пула потоков, вещей в System.Environment, Sleep и т. Д. И т. Д.
источник
Посмотрите на мой соответствующий ответ на
Разработка тестового класса для пользовательского барьера
Он смещен в сторону Java, но имеет разумное резюме вариантов.
Подводя итог, можно сказать, что (IMO) - это не какая-то причудливая структура, которая обеспечит правильность, а то, как вы разрабатываете многопоточный код. Разделение проблем (параллелизм и функциональность) имеет огромное значение для повышения доверия. Растущее объектно-ориентированное программное обеспечение, управляемое тестами, объясняет некоторые варианты лучше, чем я.
Статический анализ и формальные методы (см. Параллелизм: модели состояний и Java-программы ) - это вариант, но я обнаружил, что они имеют ограниченное применение в коммерческой разработке.
Не забывайте, что любые тесты на нагрузку / выдержку редко гарантируют освещение проблем.
Удачи!
источник
tempus-fugit
здесь свою библиотеку, котораяhelps write and test concurrent code
;)Я только недавно обнаружил (для Java) инструмент под названием Threadsafe. Это инструмент статического анализа, очень похожий на findbugs, но специально для выявления проблем с многопоточностью. Это не замена для тестирования, но я могу рекомендовать его как часть написания надежной многопоточной Java.
Он даже улавливает некоторые очень тонкие потенциальные проблемы, связанные с такими вещами, как использование классов, доступ к небезопасным объектам через параллельные классы и определение отсутствующих энергозависимых модификаторов при использовании парадигмы блокировки с двойной проверкой.
Если вы пишете многопоточную Java, попробуйте .
источник
Следующая статья предлагает 2 решения. Обертывание семафора (CountDownLatch) и добавляет функциональность, такую как вывод данных из внутреннего потока. Другой способ достижения этой цели - использовать Thread Pool (см. Раздел «Интересные места»).
Sprinkler - расширенный объект синхронизации
источник
Я провел большую часть прошлой недели в университетской библиотеке, изучая отладку параллельного кода. Центральная проблема заключается в том, что параллельный код является недетерминированным. Как правило, академическая отладка попала в один из трех лагерей здесь:
Теперь, как заметили вышеупомянутые комментаторы, вы можете превратить вашу параллельную систему в более детерминированное состояние. Однако, если вы не сделаете это правильно, вы снова вернетесь к созданию последовательной системы.
Мое предложение состояло бы в том, чтобы сосредоточиться на том, чтобы иметь очень строгий проектный протокол о том, что пронизывается, а что нет. Если вы ограничиваете свой интерфейс так, чтобы между элементами были минимальные зависимости, это намного проще.
Удачи, и продолжайте работать над проблемой.
источник
У меня была неудачная задача тестирования многопоточного кода, и это определенно самые сложные тесты, которые я когда-либо писал.
При написании своих тестов я использовал комбинацию делегатов и событий. В основном это все об использовании
PropertyNotifyChanged
событий сWaitCallback
илиConditionalWaiter
опросами.Я не уверен, что это был лучший подход, но он сработал для меня.
источник
Предполагая, что под «многопоточным» кодом подразумевается нечто, что
Другими словами, мы говорим о тестировании настраиваемого, ориентированного на состояние потока безопасного класса / метода / модуля которые в наше время должны быть очень редкими.
Поскольку этот зверь редок, прежде всего нам нужно убедиться, что есть все веские основания для его написания.
Шаг 1. Рассмотрим изменение состояния в том же контексте синхронизации.
Сегодня легко написать совместимый и асинхронный код с возможностью компоновки, в котором ввод-вывод или другие медленные операции выгружаются в фоновый режим, но общее состояние обновляется и запрашивается в одном контексте синхронизации. например, задачи async / await и Rx в .NET и т. д. - все они тестируемые по конструкции, «реальные» задачи и планировщики могут быть заменены, чтобы сделать тестирование детерминированным (однако это выходит за рамки вопроса).
Это может звучать очень ограниченно, но этот подход работает на удивление хорошо. Можно писать целые приложения в этом стиле без необходимости делать какие-либо состояния поточно-безопасными (я так делаю).
Шаг 2. Если манипулирование общим состоянием в едином контексте синхронизации абсолютно невозможно.
Удостоверьтесь, что колесо не изобретается заново, и, безусловно, не существует стандартной альтернативы, которая может быть адаптирована для работы. Вполне вероятно, что код очень сплоченный и содержится в одном блоке, например, с большой вероятностью это особый случай некоторой стандартной потокобезопасной структуры данных, такой как хэш-карта или коллекция или что-то еще.
Примечание: если код большой / охватывает несколько классов и требует многопоточных манипуляций с состоянием, тогда очень велика вероятность того, что дизайн не будет хорошим, пересмотрите Шаг 1
Шаг 3. Если этот шаг достигнут, нам нужно протестировать наш собственный настраиваемый потокобезопасный класс / метод / модуль .
Я буду абсолютно честен: мне никогда не приходилось писать надлежащие тесты для такого кода. Большую часть времени я ухожу на шаге 1, иногда на шаге 2. В прошлый раз мне приходилось писать собственный поточно-ориентированный код, который был так много лет назад, что это было до того, как я принял модульное тестирование / вероятно, мне не пришлось бы его писать с текущими знаниями в любом случае.
Если бы мне действительно нужно было протестировать такой код ( наконец, реальный ответ ), я бы попробовал пару вещей ниже
Недетерминированное стресс-тестирование. Например, запустите 100 потоков одновременно и убедитесь, что конечный результат соответствует. Это более типично для высокоуровневого / интеграционного тестирования многопользовательских сценариев, но также может использоваться на уровне устройства.
Предоставьте некоторые тестовые «зацепки», где test может внедрить некоторый код, чтобы помочь создать детерминированные сценарии, где один поток должен выполнить операцию раньше другого. Как бы ужасно это ни было, я не могу придумать ничего лучшего.
Тестирование с задержкой для запуска потоков и выполнения операций в определенном порядке. Строго говоря, такие тесты также являются недетерминированными (существует вероятность того, что система GC замораживает / останавливает мир, которая может искажать иным образом организованные задержки), также она уродлива, но позволяет избежать хуков.
источник
Для кода J2E я использовал SilkPerformer, LoadRunner и JMeter для параллельного тестирования потоков. Они все делают одно и то же. По сути, они предоставляют вам относительно простой интерфейс для администрирования своей версии прокси-сервера, необходимый для анализа потока данных TCP / IP и моделирования одновременного выполнения запросов несколькими пользователями на сервер приложений. Прокси-сервер может дать вам возможность выполнять такие вещи, как анализ выполненных запросов, представляя всю страницу и URL-адрес, отправленный на сервер, а также ответ от сервера после обработки запроса.
Вы можете найти некоторые ошибки в небезопасном режиме http, где вы можете по крайней мере проанализировать отправляемые данные формы и систематически изменять их для каждого пользователя. Но настоящие тесты - это когда вы работаете в https (Secure Socket Layers). Затем вам также придется бороться с систематическим изменением данных сеанса и файлов cookie, что может быть немного более запутанным.
Лучшая ошибка, которую я когда-либо обнаруживал при тестировании параллелизма, заключалась в том, что я обнаружил, что разработчик полагался на сборку мусора Java, чтобы при входе закрыть запрос на соединение, который был установлен при входе в систему, на сервер LDAP. к сессиям других пользователей и очень запутанным результатам, при попытке проанализировать, что произошло, когда сервер был поставлен на колени, едва способный выполнять одну транзакцию каждые несколько секунд.
В конце концов, вам или кому-то, вероятно, придется сгибаться и анализировать код на наличие ошибок, подобных тому, который я только что упомянул. И наиболее полезными являются открытые дискуссии между департаментами, подобные тем, которые произошли, когда мы раскрыли описанную выше проблему. Но эти инструменты являются лучшим решением для тестирования многопоточного кода. JMeter является открытым исходным кодом. SilkPerformer и LoadRunner являются собственностью. Если вы действительно хотите знать, является ли ваше приложение потокобезопасным, именно так поступают большие мальчики. Я сделал это для очень крупных компаний профессионально, так что я не думаю. Я говорю из личного опыта.
Предостережение: для понимания этих инструментов требуется некоторое время. Это не будет вопросом простой установки программного обеспечения и запуска графического интерфейса, если вы уже не знакомы с многопоточным программированием. Я попытался определить 3 критические категории областей для понимания (формы, данные сеансов и файлы cookie), надеясь, что, по крайней мере, начиная с понимания этих тем, вы сможете сосредоточиться на быстрых результатах, а не на том, чтобы читать через Вся документация.
источник
Параллелизм - это сложное взаимодействие между моделью памяти, аппаратным обеспечением, кэшем и нашим кодом. В случае Java, по крайней мере, такие тесты были частично рассмотрены в основном jcstress . Известно, что создатели этой библиотеки являются авторами многих функций параллелизма JVM, GC и Java.
Но даже эта библиотека нуждается в хороших знаниях спецификации Java Memory Model, чтобы мы точно знали, что мы тестируем. Но я думаю, что основное внимание в этом усилии уделяется миробенчмаркам. Не огромные бизнес-приложения.
источник
В этом примере есть статья на тему Rust в качестве языка:
https://medium.com/@polyglot_factotum/rust-concurrency-five-easy-pieces-871f1c62906a
Таким образом, хитрость заключается в том, чтобы написать вашу параллельную логику так, чтобы она была устойчивой к недетерминизму, связанному с несколькими потоками выполнения, используя такие инструменты, как каналы и condvars.
Затем, если вы так структурировали свои «компоненты», самый простой способ проверить их - использовать каналы для отправки им сообщений, а затем заблокировать другие каналы, чтобы утверждать, что компонент отправляет определенные ожидаемые сообщения.
Ссылочная статья полностью написана с использованием юнит-тестов.
источник
Если вы тестируете простой новый Thread (runnable) .run () Вы можете смоделировать Thread, чтобы запустить runnable последовательно
Например, если код тестируемого объекта вызывает новый поток, подобный этому
Затем может помочь насмешка над новыми потоками и последовательный запуск аргумента runnable.
источник
(если возможно) не используйте потоки, используйте актеры / активные объекты. Легко проверить.
источник
Вы можете использовать EasyMock.makeThreadSafe, чтобы сделать тестовый экземпляр безопасным
источник