Как протестировать многопоточную логику в java [duplicate]

Используйте map с operator.add :

>>> from operator import add
>>> list( map(add, list1, list2) )
[5, 7, 9]

или zip со списком понимание:

>>> [sum(x) for x in zip(list1, list2)]
[5, 7, 9]

Сроки сравнения:

>>> list2 = [4, 5, 6]*10**5
>>> list1 = [1, 2, 3]*10**5
>>> %timeit from operator import add;map(add, list1, list2)
10 loops, best of 3: 44.6 ms per loop
>>> %timeit from itertools import izip; [a + b for a, b in izip(list1, list2)]
10 loops, best of 3: 71 ms per loop
>>> %timeit [a + b for a, b in zip(list1, list2)]
10 loops, best of 3: 112 ms per loop
>>> %timeit from itertools import izip;[sum(x) for x in izip(list1, list2)]
1 loops, best of 3: 139 ms per loop
>>> %timeit [sum(x) for x in zip(list1, list2)]
1 loops, best of 3: 177 ms per loop

594
задан meagar 30 July 2015 в 02:00
поделиться

23 ответа

Тестирование MT-кода для корректности, как уже говорилось, является довольно сложной проблемой. В конце концов, это сводится к тому, что в вашем коде нет некорректно синхронизированных данных. Проблема заключается в том, что существует бесконечное число возможностей выполнения потоков (перемежения), над которыми у вас нет большого контроля (обязательно прочитайте эту статью ). В простых сценариях можно было бы фактически доказать правильность рассуждениями, но это обычно не так. Особенно, если вы хотите избежать / свести к минимуму синхронизацию и не пойти на самую очевидную / самую легкую синхронизацию.

Подход, который я придерживаюсь, заключается в написании высококонкурентного тестового кода, чтобы сделать потенциально необнаруженные гонки данных, которые могут происходят. И затем я запускаю эти тесты какое-то время :) Я однажды споткнулся о разговоре, где какой-то компьютерный ученый, демонстрирующий инструмент, который делает это (случайным образом разрабатывая тест из спецификаций, а затем запуская их дико, одновременно, проверяя определенные инварианты чтобы быть сломанным).

Кстати, я думаю, что этот аспект тестирования MT-кода здесь не упоминался: идентифицируйте инварианты кода, который вы можете проверить случайным образом. К сожалению, найти эти инварианты тоже довольно тяжелая проблема. Кроме того, они могут не занимать все время во время выполнения, поэтому вам нужно найти / обеспечить выполнение пунктов выполнения, где вы можете ожидать, что они будут истинными.

Некоторые интересные ссылки для чтения:

10
ответ дан bennidi 1 September 2018 в 07:02
поделиться

Посмотрите на мой ответ на

Проектирование класса Test для пользовательского барьера

Он предвзято относится к Java, но имеет разумное резюме варианты.

Подводя итог, хотя (IMO), это не использование какой-либо причудливой структуры, которая обеспечит правильность, но как вы собираетесь разрабатывать многопоточный код. Разделение проблем (параллелизм и функциональность) имеет огромный путь к повышению доверия. Растущее ориентированное на объект программное обеспечение, ориентированное на тесты , объясняет некоторые варианты лучше, чем я могу.

Статический анализ и формальные методы (см. Параллельность: модели состояний и программы Java ]) является вариантом, но я обнаружил, что они имеют ограниченное применение в коммерческой разработке.

Не забывайте, что при любых тестах типа load / soak редко можно выделить проблемы.

Удачи!

81
ответ дан Community 1 September 2018 в 07:02
поделиться

Жесткий! В моих (C ++) модульных тестах я разбил это на несколько категорий в соответствии с используемым шаблоном параллелизма:

  1. Единичные тесты для классов, которые работают в одном потоке и не являются
  2. Модульные тесты для Объекты монитора (те, которые выполняют синхронизированные методы в потоке управления вызывающих), которые выставляют синхронизированный публичный API - - создавать экземпляры нескольких потоков, реализующих API. Постройте сценарии, в которых выполняются внутренние условия пассивного объекта. Включите один более длительный тест, который в основном ударяет из него из нескольких потоков в течение длительного периода времени.
  3. Единичные тесты для Активных объектов (те, которые инкапсулируют собственный поток или потоки управления) - аналогично # 2, приведенному выше, с вариации в зависимости от дизайна класса. Открытый API может блокировать или не блокировать, вызывающие могут получать фьючерсы, данные могут поступать в очереди или должны быть удалены. Здесь возможно много комбинаций; белый ящик.

В стороне:

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

56
ответ дан David Joyner 1 September 2018 в 07:02
поделиться

(если возможно) не использовать потоки, использовать актеры / активные объекты. Легко проверить.

-3
ответ дан Dill 1 September 2018 в 07:02
поделиться

Мне нравится писать два или более тестовых метода для параллельных потоков, и каждый из них вызывает вызовы в тестируемый объект. Я использовал вызовы «Сон» () для координации порядка вызовов от разных потоков, но это не очень надежно.

Я нашел многопоточную библиотеку TC TC из той же группы, которая написала FindBugs. Он позволяет указать порядок событий, не используя Sleep (), и он надежен. Я еще не пробовал это.

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

После тщательной проверки сценариев, которые вы ожидаете вызвать, ненаучный тест, который бросает кучу одновременных запросов в классе на некоторое время, является хорошим способом поиска неожиданных проблем.

Обновление: я немного поиграл с многопоточной библиотекой TC Java, и это работает хорошо. Я также портировал некоторые свои функции в .NET-версию, которую я называю TickingTest .

5
ответ дан Don Kirkby 1 September 2018 в 07:02
поделиться

В следующей статье предлагается 2 решения. Объединение семафора (CountDownLatch) и добавление таких функций, как экстернализация данных из внутреннего потока. Другим способом достижения этой цели является использование пула потоков (см. Точки интереса).

Sprinkler - расширенный объект синхронизации

3
ответ дан Effi Bar-She'an 1 September 2018 в 07:02
поделиться

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

При написании тестов я использовал комбинацию делегатов и событий. В основном это касается использования событий PropertyNotifyChanged с WaitCallback или какого-либо ConditionalWaiter, который опроса.

Я не уверен, был ли это лучший подход, но он сработал для меня .

1
ответ дан erip 1 September 2018 в 07:02
поделиться

Недавно я открыл (для Java) инструмент под названием Threadsafe. Это инструмент статического анализа, похожий на findbugs, но специально для выявления многопоточных проблем. Это не замена для тестирования, но я могу порекомендовать его как часть надежной многопоточной Java.

Он даже захватывает некоторые очень тонкие потенциальные проблемы вокруг таких вещей, как подчинение класса, доступ к небезопасным объектам через параллельные классы и определение отсутствующих изменчивых модификаторов при использовании парадигмы с двойной проверкой.

Если вы пишете многопоточную Java , сделайте снимок.

4
ответ дан feldoh 1 September 2018 в 07:02
поделиться

Пит Гудлифф имеет серию на модульном тестировании кода с резьбой .

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

6
ответ дан graham.reeds 1 September 2018 в 07:02
поделиться

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

Самый простой способ справиться с тестовым сложным многокритериальным кодом приложения таков: если он слишком сложный для тестирования, вы делаете это неправильно. Если у вас есть один экземпляр, на котором действует несколько потоков, и вы не можете тестировать ситуации, когда эти потоки пересекаются друг с другом, тогда ваш дизайн нужно переделать. Это как просто, так и сложно.

Существует много способов программирования для многопоточности, которая позволяет избежать потоков, проходящих через экземпляры одновременно. Самое простое - сделать все ваши объекты неизменными. Конечно, это обычно невозможно. Таким образом, вам нужно определить те места в вашем дизайне, где потоки соединяются с одним и тем же экземпляром и уменьшают количество этих мест. Делая это, вы выделяете несколько классов, где на самом деле происходит многопоточность, что снижает общую сложность тестирования вашей системы.

Но вы должны понимать, что даже делая это, вы все равно не можете проверять каждую ситуацию, когда два потока наступают друг на друга. Для этого вам нужно будет одновременно запускать два потока в одном тесте, а затем точно контролировать, какие строки они выполняют в любой момент. Лучшее, что вы можете сделать, это симулировать эту ситуацию. Но это может потребовать от вас специального кода для тестирования, и это в лучшем случае на полшага к истинному решению.

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

Послушайте, поскольку в настоящее время (и, вероятно, будет стоять на хорошем времени), лучший способ протестировать многопоточные приложения - это как можно больше уменьшить сложность потокового кода. Минимизируйте области, в которых взаимодействуют потоки, проверьте как можно лучше и используйте анализ кода для определения областей опасности.

214
ответ дан Hamish Smith 1 September 2018 в 07:02
поделиться

Ожидание также может быть полезно, чтобы помочь вам написать детерминированные модульные тесты. Это позволяет подождать, пока некоторое состояние в вашей системе будет обновлено. Например:

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

или

await().atMost(5,SECONDS).until(fieldIn(myObject).ofType(int.class), equalTo(1));

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

await until { something() > 4 } // Scala example
11
ответ дан Johan 1 September 2018 в 07:02
поделиться

Если вы тестируете простой новый поток (runnable) .run () Затем вы можете приманить Thread для запуска runnable последовательно

Например, если код тестируемого объекта вызывает новый поток, подобный этому

Class TestedClass {
    public void doAsychOp() {
       new Thread(new myRunnable()).start();
    }
}

. Затем смешение новых потоков и запуск runnable-аргумента последовательно может помочь

@Mock
private Thread threadMock;

@Test
public void myTest() throws Exception {
    PowerMockito.mockStatic(Thread.class);
    //when new thread is created execute runnable immediately 
    PowerMockito.whenNew(Thread.class).withAnyArguments().then(new Answer<Thread>() {
        @Override
        public Thread answer(InvocationOnMock invocation) throws Throwable {
            // immediately run the runnable
            Runnable runnable = invocation.getArgumentAt(0, Runnable.class);
            if(runnable != null) {
                runnable.run();
            }
            return threadMock;//return a mock so Thread.start() will do nothing         
        }
    }); 
    TestedClass testcls = new TestedClass()
    testcls.doAsychOp(); //will invoke myRunnable.run in current thread
    //.... check expected 
}
0
ответ дан Josiel Faleiros 1 September 2018 в 07:02
поделиться

Я много сделал, и да, это отстой.

Некоторые советы:

  • GroboUtils для запуска нескольких тестовых потоков
  • alphaWorks ConTest для классов инструментов, чтобы вызвать перемежение между итерациями
  • Создайте поле throwable и проверьте его в tearDown (см. листинг 1 ). Если вы поймаете плохое исключение в другом потоке, просто назначьте его throwable.
  • Я создал класс utils в листинге 2 и нашел его неоценимым, особенно waitForVerify и waitForCondition, что значительно повысит производительность вашего тесты.
  • Хорошо использовать AtomicBoolean в своих тестах. Это поточно-безопасный, и вам часто понадобится конечный ссылочный тип для хранения значений из классов обратного вызова и т. П. См. Пример в листинге 3.
  • Обязательно всегда давайте вашему тесту тайм-аут (например, @Test(timeout=60*1000)), поскольку тесты на параллелизм иногда могут зависать навсегда, когда они сломаны

Листинг 1:

@After
public void tearDown() {
    if ( throwable != null )
        throw throwable;
}

Листинг 2:

import static org.junit.Assert.fail;
import java.io.File;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Random;
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.time.StopWatch;
import org.easymock.EasyMock;
import org.easymock.classextension.internal.ClassExtensionHelper;
import static org.easymock.classextension.EasyMock.*;

import ca.digitalrapids.io.DRFileUtils;

/**
 * Various utilities for testing
 */
public abstract class DRTestUtils
{
    static private Random random = new Random();

/** Calls {@link #waitForCondition(Integer, Integer, Predicate, String)} with
 * default max wait and check period values.
 */
static public void waitForCondition(Predicate predicate, String errorMessage) 
    throws Throwable
{
    waitForCondition(null, null, predicate, errorMessage);
}

/** Blocks until a condition is true, throwing an {@link AssertionError} if
 * it does not become true during a given max time.
 * @param maxWait_ms max time to wait for true condition. Optional; defaults
 * to 30 * 1000 ms (30 seconds).
 * @param checkPeriod_ms period at which to try the condition. Optional; defaults
 * to 100 ms.
 * @param predicate the condition
 * @param errorMessage message use in the {@link AssertionError}
 * @throws Throwable on {@link AssertionError} or any other exception/error
 */
static public void waitForCondition(Integer maxWait_ms, Integer checkPeriod_ms, 
    Predicate predicate, String errorMessage) throws Throwable 
{
    waitForCondition(maxWait_ms, checkPeriod_ms, predicate, new Closure() {
        public void execute(Object errorMessage)
        {
            fail((String)errorMessage);
        }
    }, errorMessage);
}

/** Blocks until a condition is true, running a closure if
 * it does not become true during a given max time.
 * @param maxWait_ms max time to wait for true condition. Optional; defaults
 * to 30 * 1000 ms (30 seconds).
 * @param checkPeriod_ms period at which to try the condition. Optional; defaults
 * to 100 ms.
 * @param predicate the condition
 * @param closure closure to run
 * @param argument argument for closure
 * @throws Throwable on {@link AssertionError} or any other exception/error
 */
static public void waitForCondition(Integer maxWait_ms, Integer checkPeriod_ms, 
    Predicate predicate, Closure closure, Object argument) throws Throwable 
{
    if ( maxWait_ms == null )
        maxWait_ms = 30 * 1000;
    if ( checkPeriod_ms == null )
        checkPeriod_ms = 100;
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    while ( !predicate.evaluate(null) ) {
        Thread.sleep(checkPeriod_ms);
        if ( stopWatch.getTime() > maxWait_ms ) {
            closure.execute(argument);
        }
    }
}

/** Calls {@link #waitForVerify(Integer, Object)} with <code>null</code>
 * for {@code maxWait_ms}
 */
static public void waitForVerify(Object easyMockProxy)
    throws Throwable
{
    waitForVerify(null, easyMockProxy);
}

/** Repeatedly calls {@link EasyMock#verify(Object[])} until it succeeds, or a
 * max wait time has elapsed.
 * @param maxWait_ms Max wait time. <code>null</code> defaults to 30s.
 * @param easyMockProxy Proxy to call verify on
 * @throws Throwable
 */
static public void waitForVerify(Integer maxWait_ms, Object easyMockProxy)
    throws Throwable
{
    if ( maxWait_ms == null )
        maxWait_ms = 30 * 1000;
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    for(;;) {
        try
        {
            verify(easyMockProxy);
            break;
        }
        catch (AssertionError e)
        {
            if ( stopWatch.getTime() > maxWait_ms )
                throw e;
            Thread.sleep(100);
        }
    }
}

/** Returns a path to a directory in the temp dir with the name of the given
 * class. This is useful for temporary test files.
 * @param aClass test class for which to create dir
 * @return the path
 */
static public String getTestDirPathForTestClass(Object object) 
{

    String filename = object instanceof Class ? 
        ((Class)object).getName() :
        object.getClass().getName();
    return DRFileUtils.getTempDir() + File.separator + 
        filename;
}

static public byte[] createRandomByteArray(int bytesLength)
{
    byte[] sourceBytes = new byte[bytesLength];
    random.nextBytes(sourceBytes);
    return sourceBytes;
}

/** Returns <code>true</code> if the given object is an EasyMock mock object 
 */
static public boolean isEasyMockMock(Object object) {
    try {
        InvocationHandler invocationHandler = Proxy
                .getInvocationHandler(object);
        return invocationHandler.getClass().getName().contains("easymock");
    } catch (IllegalArgumentException e) {
        return false;
    }
}
}

Листинг 3:

@Test
public void testSomething() {
    final AtomicBoolean called = new AtomicBoolean(false);
    subject.setCallback(new SomeCallback() {
        public void callback(Object arg) {
            // check arg here
            called.set(true);
        }
    });
    subject.run();
    assertTrue(called.get());
}
11
ответ дан Kevin Wong 1 September 2018 в 07:02
поделиться

Параллельность - сложное взаимодействие между моделью памяти, оборудованием, кэшами и нашим кодом. В случае Java, по крайней мере, такие тесты были частично рассмотрены главным образом jcstress . Создатели этой библиотеки, как известно, являются авторами многих функций параллелизма JVM, GC и Java.

Но даже эта библиотека нуждается в хорошем знании спецификации модели Java-памяти, чтобы мы точно знали, что мы тестируем. Но я думаю, что в центре внимания этих усилий были mircobenchmarks. Не огромные бизнес-приложения.

0
ответ дан Mohan Radhakrishnan 1 September 2018 в 07:02
поделиться

У меня также были серьезные проблемы с тестированием многопоточного кода. Затем я нашел действительно классное решение в «XUnit Test Patterns» Жерара Мезароса. Шаблон, который он описывает, называется Humble object.

В основном это описывает, как вы можете извлечь логику в отдельный, простой в тестировании компонент, который отделен от среды. После проверки этой логики вы можете проверить сложное поведение (многопоточность, асинхронное выполнение и т. Д.)

20
ответ дан ollifant 1 September 2018 в 07:02
поделиться

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

  1. Event-trace / replay. Для этого требуется монитор событий, а затем просмотр событий, которые были отправлены. В рамках UT это предполагает ручную отправку событий как часть теста, а затем выполнение посмертных отзывов.
  2. Сценарий. Здесь вы взаимодействуете с запущенным кодом с набором триггеров. «В x> foo, baz ()». Это можно интерпретировать в рамках UT, где у вас есть система времени выполнения, запускающая заданный тест в определенном состоянии.
  3. Интерактивный. Очевидно, что это не будет работать в условиях автоматического тестирования. ;)

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

Мое предложение состояло бы в том, чтобы сосредоточиться на очень строгом протоколе проектирования о том, что происходит с резьбой и что не получается. Если вы ограничиваете свой интерфейс так, чтобы между элементами была минимальная зависимость, это намного проще.

Удачи и продолжайте работать над проблемой.

1
ответ дан Paul Nathan 1 September 2018 в 07:02
поделиться

Для кода J2E я использовал SilkPerformer, LoadRunner и JMeter для параллельного тестирования потоков. Все они делают то же самое. В принципе, они дают вам относительно простой интерфейс для администрирования своей версии прокси-сервера, необходимый для анализа потока данных TCP / IP, и имитации нескольких пользователей, которые одновременно обрабатывают ваш сервер приложений. Прокси-сервер может дать вам возможность делать такие вещи, как анализ выполненных запросов, представление всей страницы и URL-адреса, отправленных на сервер, а также ответ от сервера после обработки запроса.

Вы можете найти некоторые ошибки в небезопасном режиме http, где вы можете хотя бы проанализировать данные формы, которые отправляются, и систематически изменять их для каждого пользователя. Но настоящие тесты - это когда вы запускаете https (Secured Socket Layers). Затем вам также придется бороться с систематическим изменением данных сеанса и файлов cookie, которые могут быть немного более запутанными.

Лучшая ошибка, которую я когда-либо обнаруживал, одновременно проверяя параллелизм, была тогда, когда я обнаружил, что разработчик полагался на сборку мусора Java, чтобы закрыть запрос на соединение, который был установлен при входе в систему, на сервер LDAP при входе в систему. Это привело к тому, что пользователи подвергались сеансам других пользователей и очень запутывали результаты при попытке проанализировать, что произошло, когда сервер был поставлен на колени, едва успев выполнить одну транзакцию каждые несколько секунд.

В конце концов, вам или кому-то, вероятно, придется пристегнуть и проанализировать код ошибок, как тот, о котором я только что упомянул. И открытая дискуссия между отделами, как и тот, который произошел, когда мы раскрыли описанную выше проблему, являются наиболее полезными. Но эти инструменты - лучшее решение для тестирования многопоточного кода. JMeter - с открытым исходным кодом. SilkPerformer и LoadRunner являются собственностью. Если вы действительно хотите знать, является ли ваше приложение потокобезопасным, вот как это делают большие мальчики. Я делал это для очень крупных компаний профессионально, поэтому я не догадываюсь. Я говорю из личного опыта.

Предупреждение: для понимания этих инструментов требуется некоторое время. Это не будет просто установка программного обеспечения и запуск графического интерфейса, если у вас уже не было возможности многопоточного программирования. Я попытался определить 3 критические категории областей для понимания (формы, сессии и данные cookie), надеясь, что, по крайней мере, начиная с понимания этих тем, вы сможете сосредоточиться на быстрых результатах, а не на том, чтобы читать полная документация.

0
ответ дан Red Rooster 1 September 2018 в 07:02
поделиться

Я обрабатываю модульные тесты резьбовых компонентов так же, как я обрабатываю любой модульный тест, то есть с инверсией элементов управления и изоляции. Я развиваюсь на .Net-арене, и из коробки очень важно, чтобы потоки (между прочим) очень сильно (я бы сказал, почти невозможно) полностью изолировать.

Поэтому я написал обертки, которые выглядят что-то вроде этого (упрощенное):

public interface IThread
{
    void Start();
    ...
}

public class ThreadWrapper : IThread
{
    private readonly Thread _thread;

    public ThreadWrapper(ThreadStart threadStart)
    {
        _thread = new Thread(threadStart);
    }

    public Start()
    {
        _thread.Start();
    }
}

public interface IThreadingManager
{
    IThread CreateThread(ThreadStart threadStart);
}

public class ThreadingManager : IThreadingManager
{
    public IThread CreateThread(ThreadStart threadStart)
    {
         return new ThreadWrapper(threadStart)
    }
}

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

Это до сих пор работало отлично для меня, и я использую тот же подход для пула потоков, вещи в System.Environment, Sleep и т. д. и т. д.

5
ответ дан scim 1 September 2018 в 07:02
поделиться

Для Java см. главу 12 из JCIP . Существуют некоторые конкретные примеры написания детерминированных многопоточных модульных тестов, чтобы, по крайней мере, проверить правильность и инварианты параллельного кода.

«Доказательство» безопасности потоков с модульными тестами является гораздо более сложным. Я убежден, что это лучше всего обеспечивается автоматическим интеграционным тестированием на различных платформах / конфигурациях.

6
ответ дан Scott Bale 1 September 2018 в 07:02
поделиться

Другой способ (kinda) проверить резьбовой код и очень сложные системы в целом - через Fuzz Testing .

Цитата:

Fuzz testing или fuzzing - это программное обеспечение. Это не очень хорошо, и он не найдет всего, но его, вероятно, будет полезно и просто сделать. который предоставляет случайные данные («пух») на вкладки программы. Если программа выйдет из строя (например, сбой или отказ от встроенных кодовых утверждений), можно отметить дефекты. Большим преимуществом тестирования fuzz является то, что тестовый дизайн чрезвычайно прост и свободен от предвзятых представлений о поведении системы.

...

Тест Fuzz часто используется в крупных проектах разработки программного обеспечения, которые используют тестирование черного ящика. Эти проекты, как правило, имеют бюджет для разработки тестовых инструментов, а тестирование fuzz - это одна из тех методик, которая обеспечивает высокий коэффициент соотношения затрат и затрат.

...

Тем не менее, тестирование fuzz не заменяет исчерпывающее тестирование или формальные методы: оно может обеспечить только случайную выборку поведения системы и во многих случаях передавать Тест fuzz может только продемонстрировать, что часть программного обеспечения обрабатывает исключения без сбоев, а не ведет себя правильно. Таким образом, тестирование fuzz можно рассматривать только как инструмент поиска ошибок, а не гарантию качества.

9
ответ дан ThomasH 1 September 2018 в 07:02
поделиться

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

-4
ответ дан user590444 1 September 2018 в 07:02
поделиться

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

Написание тестового многопоточного кода

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

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

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

Написание модульных тестов для многопоточного кода

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

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

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

Наконец, отслеживайте количество ошибок, обнаруженных в вашем тесте. Если ваш тест содержит 80% кода, можно ожидать, что он поймает около 80% ваших ошибок. Если ваш тест хорошо разработан, но не обнаруживает ошибок, существует разумная вероятность того, что у вас нет дополнительных ошибок, которые будут отображаться только в процессе производства. Если тест поймает одну или две ошибки, вам все равно повезет. Помимо этого, и вы можете подумать о тщательном просмотре или даже полном переписывании кода обработки потоков, так как вполне вероятно, что код по-прежнему содержит скрытые ошибки, которые будет очень сложно найти до тех пор, пока код не будет создан, и очень трудно установить.

33
ответ дан Warren Dew 1 September 2018 в 07:02
поделиться

Есть несколько инструментов вокруг, которые неплохие.

Некоторые хорошие инструменты статического анализа включают в себя FindBugs (дает некоторые полезные подсказки), JLint , Java Pathfinder (JPF & JPF2) и Bogor .

MultithreadedTC - довольно хороший инструмент динамического анализа (интегрированный в JUnit ), где вам нужно настроить свои собственные тестовые примеры.

ConTest из IBM Research интересен.

SPIN - это действительно классный инструмент для моделирования Java-приложений. (и других) компонентов, но вам нужно иметь некоторую полезную структуру. Трудно использовать, как есть, но очень мощный, если вы знаете, как его использовать. Несколько инструментов используют SPIN под капотом.

MultithreadedTC, вероятно, является наиболее популярным, но некоторые из инструментов статического анализа, перечисленных выше, безусловно, стоит посмотреть.

16
ответ дан xagyg 1 September 2018 в 07:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: