__>в алгоритмах есть можно сказать "точки разрыва" — когда поведение меняется. то есть есть ф-ия, например, которая число печатает. переход от одной цифры к двум — такая "тока разрыва непрерывности решения". да, мы можем нагенерировать тонну, там, списков для проверки правильно работы убирания дубликатов, но разумнее специфицировать это примерно так:
__>[] -> [] // это спецификация на "невалидные данные"
__>[a] -> [a] // на данные, которые не нужно обрабатывать
__>[a, a] -> [a] // простейший пример
__>[a, a, a] -> [a] // а то вдруг там иф будет стоять, который пару схлопнет, а тройку нет
__>[a, b, a] -> [a, b] // дубликат, стоящий неподряд
__>[b, a, b, a] -> [b, a] // два дубликата неподряд
__>[a, b, c, b] -> [a, b, c] // убираем не первую букву (а то в остальных тестах она у нас че-то первая стоит)
__>минимальный код, который будет проходить эти тесты, должен будет убирать дубликаты по-нормальному
Это все идеальная утопическая ситуация. На практике все гораздо сложнее. Ты, например, в своей «спецификации» не описал толпу вариантов, которые, в зависимости от того, насколько сложная функция уборки дупликатов, могут сработать, а могут не сработать.
Два интересных примера тут:
https://youtu.be/zi0rHwfiX1Q?t=18m57s
На quiviq'овских воркшопах приводят другие интересные примеры из реальных ситуаций, когда программисты забывают тестировать пограничные значения.
Например, код сериализации для SMS-gateway'я, который вылетал на данных размером, кратных 2^8, хотя все тесты проходили. Ну, как тесты. Там был тест типа твоей «спецификации». Три строчки типа
— serialize("A") == 65
— serialize("") == -1
— deserialize(serialize("A")) == "A"