Генерировать или валидировать?
Как известно, я люблю автоматизировать всякую дичь (например, 1, 2, 3, 4). Один из видов такой дичи — проверка того, что разные части приложения соответствуют друг другу и/или что тестами покрыто все, что нужно. В основном из-за недоверия к кожаным мешкам.
Приведу примеры:
- проверка того, что все модули системы покрыты тестами и включены в основной конфиг. Причем немного извращенная, потому что сверялись три места в коде: список основных классов, список классов тестов и список классов в основном конфиге приложения.
- проверка соответствия REST-клиентов соответствующим микросервисам. Куча рефлексии, чтобы проверить, что если вызвать все методы клиента со всеми параметрами, то будут вызваны все выставленные эндпоинты и покрыты все параметры и тело запроса.
- покрытие тестами схем камунды, о котором уже писал.
- проверка, что json-схема, маппинг Elasticsearch и swagger соответствуют друг другу.
Казалось бы, это странные операции. Ведь для проверки покрытия есть специальные утилиты, а такие вещи, как swagger, клиенты для REST легко генерируются. Но, как говорится, есть нюансы.
Средства покрытия не могут проверить все (например, все, что не является кодом) и их точность завязана на строчки кода. 100% покрытия редко достижимы, обычно это в районе 80-90%. Подразумевается, что в эти 10-20% попадает всякая служебная фигня, но никто не гарантирует, что это не окажется ядро системы. Кроме того, редко когда плохое покрытие блокирует релиз, да и мало кто смотрит эти отчеты. А вот если они валят тесты, то это уже повод что-то сделать (можно сделать таск на билде для завала по покрытию, но это обычно гемор).
Генерация — хорошая штука (в конце концов, код — это DSL для генерации машинного кода), но результат все равно придется как-то проверять. Можно довериться разработчикам генераторов, но никто не отменял garbage in → garbage out. Однако не на всякую дичь есть генератор, а хорошо написать свой — не очень тривиально. Сложно учесть все требования и нюансы, надо адекватно встраивать генерацию в процесс сборки, некоторые вещи все равно придется дописывать руками (какие-нибудь описания). Кроме того, страдает гибкость: в сгенерированном API-клиенте уже не затащишь два http-запроса в один метод, в swagger не детализируешь, что там в кишках json, который отдается as is из базы и т.п. Наконец, генерация — процесс с потерей информации, и если нет единого источника правды, который содержит ее полностью, то появляется дополнительная сущность, из которой генерируются остальные.
А написать проверку, что все соответствует друг-другу — довольно просто. И все сущности доступны напрямую из репозитория, ими легко поделиться (если это какой-нибудь контракт, например). Можно не заморачиваться с прокидыванием метаинформации (всякие описания полей) — ее все равно проверить может только человек. Ему правда писать придется чуть больше, но обычно это имеет позволительную цену. Лучше иметь явный тест, чем строчку в чек-листе код-ревью.