Re[2]: дебагинг vs unit-тесты
От: Stanislav V. Zudin Россия  
Дата: 30.04.16 22:56
Оценка:
Здравствуйте, landerhigh, Вы писали:
L>Предположим, что у нас и правда завелась функция
L>пишем тест для нее. Естественно, предполагается, что у нас есть оператор сравнения двух матриц.
...

L>
L>TEST(transposeMatrix, testThatShouldNotExist)
L>{
L>    Matrix mtx = ...; // Тут инициализация квадратной матрицы
L>    Matrix expected = ...; // Вручную инициализированная транспонированная матрица
L>    mtx = transpose(mtx);
L>    ASSERT_EQ(expected, mtx);
L>


Я думал, что у тебя есть секретная комба - ломик в рукаве, поэтому у тебя получается, а у меня — ни фига.
А оказывается, я делаю всё то же самое.

Ты вот говоришь, что код, мол, неправильный.

SVZ>Не всегда просто и нифига не быстро.
Если не просто и не быстро, то вы либо не понимаете свой собственный код, либо алгоритм, либо предметную область. Значит, нужно заполнять пробелы.
SVZ>В моей практике это сложно и геморройно. И еще объемно.
Хороший индиактор того, что тестируемый код пора дробить на части.


А я думаю, что проблема не в коде, а в прикладной области и в решаемых задачах.
Есть алгоритмы, у которых на вход подается крошечный набор данных и легко проверить результат.
В качестве примера — Poco (недавно ковырял). Там, действительно все тесты по 5-10 строк. Такие тесты можно клепать по дюжине в час.

Вот если взять твой пример с матрицей и спроецировать его, скажем, на построение адаптивной сетки (adaptive mesh refinement — можно погуглить картинки), то что у нас получается.

Вот эта инициализация:
L> Matrix mtx = ...; // Тут инициализация квадратной матрицы
L> Matrix expected = ...; // Вручную инициализированная транспонированная матрица

Может занимать до сотни строк.
И еще столько же — проверка результатов.

Ну и тестов надо написать хренову тучу.

Что придется тестировать:
Случай 1. Сетка из одной ячейки.
Подготовка данных занимает одну строчку кода, затем надо проверить, что все 6 граней инцидентны "воздуху".
Теперь ячейку надо рассечь.
Варианты сечения: по осям X, Y, Z, X+Y, X+Z, Y+Z, X+Y+Z. Итого 7 вариантов сечения. В результате получается от 2 до 8 ячеек.
Теперь нужно найти положение ячеек относительно соседей (не одна строчка). Затем проверить, что на периферии ячейки по-прежнему инцидентны воздуху, а внутри соединены между собой.

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

Случай 3. Сверху и снизу добавляем ячеек — получаем "кубик" 3х3х3 ячеек. Снова ищем центральную ячейку и все по новой. Сложность проверки возрастает, т.к. любое (почти любое) сечение затрагивает соседей в нескольких слоях.

Случай 4. Тут самое интересное. Т.к. каждая ячейка своей гранью может соприкасаться только с 0, 1, 2 и 4 ячейками, то при определенных сечениях возникает конфликт, чтобы его разрешить необходимо подразбить соседа — начинается лавинообразный процесс. Как тут писать тест — у меня фантазии уже нет.

Итого. Чтобы запрограммировать алгоритм потребуется 1-2 недели и еще пара недель, как минимум, чтобы обложить его тестами, от которых будет хоть какой-то прок.
Что интересно, когда код будет отлажен никто в него не полезет. А если полезет, то это означает, что предстоят очень серьезные изменения, которые могут перекроить все структуры данных и тогда написанные тесты пойдут псу под хвост.

Как в таких условиях извлечь из юнит-тестов какую-то пользу — я пока не представляю.
_____________________
С уважением,
Stanislav V. Zudin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.