Единичное тестирование больших наборов данных?

Какой лучший способ для больших наборов данных unit test? Некоторые устаревшие коды, которые я поддерживаю, имеют структуры из ста членов или более; другие части кода, которые мы работаем над созданием или анализом наборов данных из сотен образцов.

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

Есть ли лучшие решения?

Ответ 1

Если вы пытаетесь достичь, на самом деле, unit test вы должны издеваться над базовыми структурами данных и имитировать данные. Этот метод дает вам полный контроль над входами. Например, каждый написанный вами тест может обрабатывать одну точку данных, и у вас будет очень сжатый набор тестов для каждого условия. Есть несколько открытых систем с открытым исходным кодом, я лично рекомендую Rhino Mocks (http://ayende.com/projects/rhino-mocks/downloads.aspx) или NMock (http://www.nmock.org).

Если вы не можете издеваться над структурами данных, я рекомендую рефакторинг, чтобы вы могли:-) Его стоит! Или вы также можете попробовать TypeMock (http://www.typemock.com/), который позволяет насмехаться над конкретными классами.

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

Ответ 2

Это по-прежнему жизнеспособный подход. Хотя, я бы классифицировал это как функциональный тест или просто не чистый unit test. Хорошим unit test будет выборка из тех записей, которая дает хорошее распределение случаев кросс, с которыми вы можете столкнуться, и записывать их. Затем у вас есть ваш последний "прием" или "функциональный" тест с вашим массовым тестом на все данные.

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

Ответ 3

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

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

Например, ваши сериализованные данные могут быть преобразованы в:

unsigned char mySerialisedData[] = { 0xFF, 0xFF, 0xFF, 0xFF, ... };

test()
{
    MyStruct* s = (MyStruct*) mySerialisedData;

}

Для более подробного примера (в С#) см. этот unit test. В нем показан пример использования некоторых жестко закодированных сериализованных данных в качестве входных данных для тестов, подписание тестовой сборки.