Я часто пишу модульные тесты, чтобы доказать, что некоторый набор кода является поточно-ориентированным.Обычно я пишу эти тесты в ответ на ошибку, обнаруженную в производстве.В этом случае целью теста является демонстрация того, что ошибка реплицируется (тест не пройден), и что новый код устраняет проблему с многопоточностью (тесты проходят), а затем действует как регрессионный тест для будущих выпусков.
Большинство тестов безопасности потоков, которые я написал, проверяют состояние гонки потоков, но некоторые также проверяют наличие взаимоблокировок потоков.
Упреждающее модульное тестирование этого кода является потоком Сейф немного сложнее.Не потому, что написать модульный тест сложнее, а потому, что вам нужно провести тщательный анализ, чтобы определить (на самом деле, действительно), что может быть небезопасным для работы с потоками.Если ваш анализ верен, то вы сможете написать тест, который не будет выполнен, пока вы не сделаете поток кода безопасным.
При тестировании на состояние состязания потоков мои тесты почти всегда следуют той же схеме: (этотакое псевдокод)
boolean failed = false;
int iterations = 100;
// threads interact with some object - either
Thread thread1 = new Thread(new ThreadStart(delegate() {
for (int i=0; i<iterations; i++) {
doSomething(); // call unsafe code
// check that object is not out of synch due to other thread
if (bad()) {
failed = true;
}
}
});
Thread thread2 = new Thread(new ThreadStart(delegate() {
for (int i=0; i<iterations; i++) {
doSomething(); // call unsafe code
// check that object is not out of synch due to other thread
if (bad()) {
failed = true;
}
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
Assert.IsFalse(failed, "code was thread safe");