Покрытие валидационных правил в контексте схем, построенных на основе библиотеки Yup, означает степень, с которой тесты охватывают все возможные ветви, условия и ограничения, заданные валидационной схемой. В отличие от классического покрытия кода, здесь анализируется не только выполнение строк, но и полнота проверки логики данных: обязательные поля, типы, ограничения длины, диапазоны, условные зависимости и трансформации.
Валидационная схема в Yup представляет собой декларативное описание структуры данных, где каждое правило формирует отдельную точку риска. Недостаточное покрытие приводит к тому, что часть правил остаётся нефункциональной или непроверенной, что проявляется только в рантайме при некорректных входных данных.
Схемы Yup обычно состоят из комбинации базовых и составных правил:
string, number,
boolean, array, object)min, max,
length, matches)required)transform)when)test)Каждый из этих элементов формирует отдельный класс проверок, требующих индивидуального тестового покрытия. Например, схема:
const schema = Yup.object({
username: Yup.string()
.min(3)
.max(20)
.required(),
age: Yup.number()
.min(18)
.max(65),
email: Yup.string()
.email()
.required()
});
имеет как минимум следующие независимые ветви покрытия:
usernameusername меньше минимумаage (валидно, но важно проверить)age ниже или выше диапазонаКаждое правило должно рассматриваться как отдельная логическая ветка.
Особое внимание требуется схемам с использованием when,
где логика валидации зависит от других полей:
const schema = Yup.object({
isCompany: Yup.boolean(),
companyName: Yup.string().when('isCompany', {
is: true,
then: (schema) => schema.required(),
otherwise: (schema) => schema.notRequired()
})
});
Здесь покрытие включает минимум два состояния:
isCompany = true → поле обязательноisCompany = false → поле не проверяется на
обязательностьОтсутствие теста хотя бы одного из сценариев означает неполное покрытие логики схемы, даже если код формально выполняется.
В Yup значительное количество ошибок возникает на границах диапазонов. Поэтому покрытие должно включать не только валидные значения, но и предельные состояния:
min)max)Пример для числового поля:
Yup.number().min(10).max(20)
Требуемые сценарии покрытия:
Аналогичный принцип применяется к строкам и массивам, где важны длина и количество элементов.
Метод test() в Yup создаёт произвольные условия, часто
содержащие бизнес-логику. Это один из наиболее критичных элементов с
точки зрения покрытия.
Yup.string().test(
'no-special-chars',
'Недопустимые символы',
(value) => /^[a-zA-Z0-9]+$/.test(value)
);
Минимальный набор покрываемых случаев:
undefined или null (если не требуется
обязательность)Каждый test() фактически формирует отдельную функцию,
требующую полного ветвления условий.
В Yup различаются состояния:
required()notRequired()nullable()Комбинации этих модификаторов создают дополнительные ветви логики:
Yup.string().nullable().required()
Возможные сценарии:
null → невалидноundefined → невалидноНедостаточное покрытие часто возникает, когда тестируются только валидные значения без проверки всех форм отсутствия данных.
Метод transform() изменяет входные данные перед
валидацией, что добавляет скрытый слой логики:
Yup.number().transform((value, originalValue) =>
originalValue === '' ? null : value
);
Покрытие должно учитывать:
NaN и некорректные типыИгнорирование трансформаций приводит к ложному ощущению корректности схемы, так как тестируется итоговое состояние, но не процесс преобразования.
Для сложных схем используется структурирование покрытия:
| Тип правила | Сценарии проверки |
|---|---|
| required | есть / отсутствует / null |
| min/max | ниже / на границе / выше |
| string format | корректный / некорректный |
| when | true / false условия |
| test | true / false / edge / null |
| transform | исходные типы и преобразованные значения |
Такое представление позволяет выявить непокрытые комбинации условий.
При увеличении числа полей возникает эффект комбинаторного роста возможных состояний. Например, схема из 5 полей с 3 состояниями на каждое уже даёт 243 возможные комбинации.
Yup не требует полного перебора всех комбинаций, но критически важные пересечения должны покрываться:
when)На практике чаще всего отсутствует проверка следующих случаев:
undefined вместо nullwhen, проверенные только в одной веткеtest() без отрицательных сценариевДля анализа покрытия используются тестовые фреймворки (например, Jest), где каждая ветка схемы проверяется отдельно через вызов:
schema.isValid(data)
schema.validate(data)
Разделение на позитивные и негативные сценарии позволяет явно фиксировать отсутствие веток.
Дополнительно применяется подход изоляции схем:
Yup поддерживает вложенные структуры:
Yup.object({
user: Yup.object({
profile: Yup.object({
age: Yup.number().required()
})
})
});
Покрытие должно учитывать:
Ошибки на глубине часто не выявляются при поверхностных тестах верхнего уровня.
Покрытие валидационных правил считается неполным без отрицательных сценариев. В Yup это особенно важно, так как библиотека ориентирована на декларативное описание ограничений, где отсутствие проверки равносильно пропуску правила.
Отрицательные сценарии включают:
Без них схема формально существует, но не выполняет защитную функцию.