Comments 4
Было бы гораздо лучше, если бы Вы ничего не придумывали, а просто вникли в теорию чуть глубже.
Вы же сами пишите, что "минимальное число тестов, обеспечивающих выполнение всего кода, будет равно цикломатической сложности."
До этого вы писали, что на тестах лучше экономить и сокращать их число.
Из этих двух тезисов без всяких выдумываний "прямолинейности кода" выходит, что циклометрическую сложность надо снижать. Для этого есть вполне себе известные инструменты. Некоторые из них Вы перечислили. Применяем (но не доводя до абсурда), и получаем уменьшение стоимости тестирования системы. Точка.
Название "цикломатическая сложность", как мне кажется, менее наглядное, чем "прямолинейность". Поэтому правило "чем "прямей" код, тем меньше нужно тестов", мне кажется более простым.
Если мы не ставим себе задачу обязательно выполнять весь код на этапе запуска тестов, то это минимальное число тестов может быть снижено ещё дальше. Компилятор за нас вполне может выполнить проверку каждой строчки кода. А если мы будем использовать типы данных, выведенные из требований, то проверка, выполненная компилятором, даст больше гарантий качества, чем мы могли бы получить, добавляя тестов.
Кстати, стоит добавить, что качество ПО вполне себе измеряемая величина. Для ее измерения существует подход, называемый мутационным тестированием. Он как раз и считает сколько раз в вашем коде можно ошибиться, например, инвертировав условие в операторе ветвления, и сколько из этих ошибок мы отлавливаем тестами.
Зная, общее число ошибок, мы можем проверить, реагирует ли хоть один тест на каждую из имеющихся ошибок. Если реагирует, то мы защищены от такой ошибки. Отношение ошибок, от которых мы защищены, к общему числу ошибок и дает нам качественный показатель нашего ПО.
Если честно, я не сталкивался в реальных проектах с успешным применением мутационного тестирования.
Для кода, в котором полно операторов if, такое тестирование, по-видимому, можно реализовать.
Я здесь выступаю за то, чтобы минимизировать количество if'ов и по-максимуму использовать развитые типы данных. Я затрудняюсь предположить, что может "мутировать" автоматика в таком коде:
val f: [A] => A => A = [A] => (a: A) => a
?
Бестолковые тесты versus качественное ПО. Часть 2. Что делать? 2. «Распрямляем» код