Как мне выполнить модульное тестирование многопоточного кода?

  1. Pop top row
  2. Переставить и перевернуть вверх дном (то же, что и вращать на 90 градусов против часовой стрелки)
  3. Перейти к 1

Код Python:

import itertools

arr = [[1,2,3,4],
       [12,13,14,5],
       [11,16,15,6],
       [10,9,8,7]]

def transpose_and_yield_top(arr):
    while arr:
        yield arr[0]
        arr = list(reversed(zip(*arr[1:])))

print list(itertools.chain(*transpose_and_yield_top(arr)))
651
задан meagar 30 July 2015 в 02:00
поделиться

13 ответов

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

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

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

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

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

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

233
ответ дан undur_gongor 30 July 2015 в 02:00
поделиться

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

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

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

1
ответ дан erip 30 July 2015 в 02:00
поделиться

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

я нашел библиотека Multithreaded TC Java от той же группы, которая записала FindBugs. Это позволяет Вам определить порядок событий, не используя Сон (), и это надежно. Я еще не попробовал его.

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

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

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

5
ответ дан Don Kirkby 30 July 2015 в 02:00
поделиться

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

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

6
ответ дан Scott Bale 30 July 2015 в 02:00
поделиться

у Pete Goodliffe есть ряд на поблочное тестирование потоковых код.

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

6
ответ дан graham.reeds 30 July 2015 в 02:00
поделиться

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

Кавычка:

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

...

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

...

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

13
ответ дан ThomasH 30 July 2015 в 02:00
поделиться

У меня также были серьезные проблемы, тестирующие мульти - распараллелил код. Тогда я нашел действительно прохладное решение в "xUnit Тестовые Шаблоны" Gerard Meszaros. Шаблон, который он описывает, называют Скромный объект .

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

21
ответ дан ollifant 30 July 2015 в 02:00
поделиться

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

Некоторые подсказки:

  • 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 30 July 2015 в 02:00
поделиться

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

  1. Модульные тесты на классы, которые работают в единственном потоке и не ориентированы на многопотоковое исполнение - легкий, протестируйте, как обычно.

  2. Модульные тесты на объекты Монитора (те, которые выполняют синхронизированные методы в потоке вызывающих сторон управления), которые представляют синхронизируемый общедоступный API - инстанцируют нескольких ложных потоков, которые осуществляют API. Создайте сценарии, которые осуществляют внутренние условия пассивного объекта. Включайте один более длинный запускающий тест, который в основном бьет heck из него от нескольких потоков в течение длительного периода времени. Это является ненаучным, я знаю, но это действительно создает атмосферу доверия.

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

Как в стороне:

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

59
ответ дан David Joyner 30 July 2015 в 02:00
поделиться

Это было некоторое время, когда этот вопрос был отправлен, но этому все еще не отвечают...

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

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

Это - идея из книги Gerard Meszardos" Тестовые Шаблоны xUnit " и названо "Скромным Объектом" (p. 695): необходимо разделить код логики ядра и что-либо, что пахнет как асинхронный код друг от друга. Это закончилось бы к классу для логики ядра, которая работает синхронно .

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

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

Что-либо выше того (тестирование взаимодействия между классами) является тестами компонента. Также в этом случае необходимо быть в состоянии иметь неограниченный контроль над синхронизацией, если Вы придерживаетесь "Скромного Объектного" шаблона.

88
ответ дан Community 30 July 2015 в 02:00
поделиться
  • 1
    @SaucyK: Я знаю, что API доступен онлайн, но очевидно я пропускаю что-то, и я хочу зафиксировать его. – LuckyLuke 8 July 2011 в 15:41

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

  1. Event-trace/replay. Это требует монитора события и затем рассмотрения событий, которые были отправлены. В платформе UT это включило бы вручную отправку событий как часть теста и затем выполнение посмертных обзоров.
  2. Scriptable. Это - то, где Вы взаимодействуете с рабочим кодом с рядом триггеров. "На x> нечто, baz ()". Это могло быть интерпретировано в платформу UT, где у Вас есть система во время выполнения, инициировавшая данный тест на определенном условии.
  3. Интерактивный. Это, очевидно, не будет работать в автоматической ситуации с тестированием.;)

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

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

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

1
ответ дан Paul Nathan 30 July 2015 в 12:00
поделиться

Я обрабатываю модульные тесты многопоточных компонентов так же, как и любые модульные тесты, то есть с инверсией структур управления и изоляции. Я разрабатываю на .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
ответ дан 22 November 2019 в 21:44
поделиться

Есть несколько неплохих инструментов. Вот краткое изложение некоторых из них.

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

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

ConTest от IBM Research представляет интерес. Он инструментирует ваш код, вставляя все виды поведения, изменяющие поток (например, сон и выход), чтобы попытаться случайным образом обнаружить ошибки.

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

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

19
ответ дан 22 November 2019 в 21:44
поделиться
Другие вопросы по тегам:

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