Эссе о валидации данных |
17.10.2009 15:15 |
В комментариях к заметке "Можно ли делить на 0,01 ?" я обещал написать отдельный пост, посвященный валидации данных, которые приложения получают извне -- от пользователя, от других программ, из файлов и т.д. Кроме того, не так давно эта тема вновь ненадолго возникла в обсуждении заметки "Проверка экранных форм". Так что, видимо, пришло время обсудить этот вопрос в деталях. Мы рассмотрим три вопроса -- 1) зачем вообще нужна валидация данных, и 2) где и когда может выполняться валидация данных, 3) какие бывают разновидности проверок. Зачем нужна валидация данных?Казалось бы, "невалидные" данные, не удовлетворяющие определённым ограничениям, могут вызвать сбой в работе программы. Но что это означает? Предположим, в каком-то месте программы возникает исключение при попытке преобразовать строку в число, если строка имеет некорректный формат. Разумеется, если исключение не будет нигде перехвачено, это может привести к аварийному завершению программы. Но это маловероятный сценарий развития событий. Скорее всего в каком-то месте сработает перехватчик, который либо выдаст пользователю какое-то сообщение об ошибке в программе, либо сделает запись в журнал ошибок, после чего программа постарается восстановиться от сбоя и продолжить работу. То есть даже если валидацию не выполнять, вполне вероятно, что ничего страшного не случится. Но определённые негативные последствия у отсутствия валидации всё таки могут быть, давайте чуть подробнее рассмотрим, какие проблемы при этом могут возникнуть.
Короче говоря, отсутствие валидации может приводить к вышеописанным (а может быть и ещё каким-то другим) проблемам. Соответственно, наличие валидации позволяет предотвратить серьёзные сбои, упрощает идентификацию проблем, но за это приходится расплачиваться производительностью, поскольку дополнительные проверки увеличивают нагрузку на систему. И тут мы переходим ко второму вопросу - как уменьшить эту дополнительную нагрузку. Где и когда выполнять валидацию данных?Как уже было сказано выше, с точки зрения уменьшения нагрузки лучше всего вообще не выполнять валидацию данных. Но если всё-таки проверка нужна, логика подсказывает, что удобно проверять данные в том месте, где они попадают в программу из внешнего мира. После такой проверки можно быть уверенным, что в программу попадают правильные данные и в дальнейшем они могут использоваться без дополнительных проверок. Это может быть пользовательский интерфейс, через который человек вводит данные. Это может быть файл, содержащий настройки программы или данные, которые программа должна обработать. Это может быть база данных, в которую информация может попадать из других программ. Это может быть сетевой протокол обмена данными с другими программами. Наконец, это может быть программный интерфейс, который использует другая программа, вызывая некоторые функции/процедуры и передавая в них параметры. Увы, здравый смысл иногда вынужден отступить перед натиском действительности. «Фейс-контроль» данных на входе иногда не просто нецелесообразен, но вообще невозможен. Ниже приведены некоторые причины этого.
Как выполнять валидацию данных?Впрочем, где бы ни выполнялась валидация, можно это делать несколькими различными способами, в зависимости от того, какие ограничения накладываются на данные.
Транзакция -- это последовательность действий, которые либо все завершаются успешно, либо происходит какой-то сбой при выполнении отдельного действия, и тогда отменяются результаты всех предыдущих действий этой цепочки. Так вот, валидацию можно выполнять в процессе выполнения транзакции, а последняя проверка может быть выполнена в самом конце транзакции по обработке данных. При этом мы валидируем уже не сами данные, а то состояние, которое получилось после их полной обработки, и если это состояние не удовлетворяет каким-то ограничениям, тогда мы признаём входные данные невалидными и возвращаем всё к исходному состоянию. Какой способ валидации следует применять на практике в том или ином случае? Чаще всего одним способом ограничиться не удаётся, да и не нужно. Валидацию данных можно и нужно выполнять в несколько этапов, усложняя проверки. Сначала, по мере ввода, следим за тем, чтобы данные не содержали недопустимых символов. Например, для числового поля пользователю может быть запрещён ввод нецифровых символов. После того, как ввод завершён, можно проверить всё значение целиком. Для введённого числа могут быть какие-то ограничения, например, оно не должно превышать определённого максимального допустимого значения. Если наше числовое поле представляет собой возраст, оно должно находиться в пределах от 0 до, скажем, 120. Когда заполнены все поля, можно проверить, согласованы ли введённые значения друг с другом. Например, если в форме кроме поля для указания возраста есть поле для ввода номера паспорта, приложение может проверить, что при заполнении номера паспорта возраст должен быть не менее 14 лет. Наконец, если всё введено корректно, можно попытаться начать обработку, выполняя проверки по ходу дела, а также в самом конце, и если что-то пошло не так, выполнить откат к исходному состоянию. Ну и, конечно же, проверки на следующем уровне могут подстраховывать проверки предыдущих уровней. Скажем, для веб-приложений обязательной является проверка данных, пришедших на сервер в HTTP-запросе, независимо от того, выполнялась ли перед этим предварительная валидация в браузере или нет. Причина этого в том, что проверку на клиентской стороне можно обойти. Для других видов приложений обойти проверки не так просто, но иногда тоже вполне возможно, как показано в примере чуть ниже. Тестирование валидаторовЗавершим статью демонстрацией различных видов валидаторов, а также некоторыми рекомендациями относительно того, как при тестировании проверять правильность их работы. Начнём с посимвольной проверки. Графический редактор Paint, диалог изменения размеров рисунка, ширина рисунка. В это поле допускается вводить только цифры, при попытке ввести другие символы выдаётся сообщение об ошибке: Однако, проявив смекалку, можно обойти эту валидацию вводимых символов: через буфер обмена удаётся вставить в это поле отрицательное число, несмотря на то, что минус является недопустимым символом: Впрочем, это не приводит к негативным последствиям, потому что на следующем уровне стоит ещё одна проверка, которая срабатывает при нажатии кнопки OK: Есть и другие ограничения для этого поля, которые тоже проверяются после нажатия кнопки OK: А вот находящееся совсем рядом в том же диалоге поле для ввода наклона рисунка не содержит валидации символов, несмотря на то, что это тоже числовое поле. Более того, при вводе недопустимых символов после нажатия OK можно увидеть вот такое странное сообщение, практически не поддающееся расшифровке: Все вышеописанные примеры связаны с проверкой отдельно взятого поля. Пример валидации комбинации полей можно найти в том же приложении, но в другом месте -- в диалоге настройки параметров страницы для печати. Если указать размеры полей страницы так, чтобы в сумме они превосходили ширину страницы, получим вот такое сообщение: Ну и, наконец, в заметке "Почему не хватает памяти, чтобы уменьшить размеры рисунка?" описана ошибка, связанная с тем, что в этом графическом редакторе отсутствует корректная обработка сбоев и откат транзакции при слишком сильном увеличении размера рисунка. Тестировщику необходимо все эти ситуации отрабатывать. Во-первых, нужно проверять валидацию на всех уровнях. Во-вторых, нужно проверять согласованность валидаторов на разных уровнях. В-третьих, надо искать пути обхода валидаторов, пытаясь добраться до следующего уровня без предварительных проверок. ЗаключениеБольшая часть этой статьи посвящена не способам тестирования валидаторов, а описанию их устройства. Почему? Потому что врага надо знать в лицо. Чтобы найти дефект валидации данных, надо понимать, где искать и на что обращать внимание. Обсудить в форуме |