Основы тестирования и отладки Веб-приложений
Презентацию к данной лекции Вы можете скачать здесь.
19.1. Тестирование Веб-приложений
19.1.1. Введение
Вычислительные и коммуникационные системы используются все чаще и с каждым днем все глубже входят в нашу повседневную жизнь. Компании и отдельные пользователи все больше зависят в своей работе от web-приложений. Веб-приложения соединяют различные отделы внутри компаний, различные компании и простых пользователей. Веб-приложения очень динамичны, а их функциональные возможности непрерывно растут. Непрерывно возрастает потоковый трафик средств информации и запросов, формируемых переносными и встроенными устройствами. Вследствие этого возрастает сложность систем такого рода. Очевидно, что для понимания, анализа, разработки и управления такими системами нужны количественные методы и модели, которые помогают оценить различные сценарии функционирования, исследовать структуру и состояние больших систем. Наблюдаются тенденции к постоянному росту спроса на Веб-службы. Таким образом, проблемы, связанные с недостаточной производительностью будут возникать и в будущем, и, в конце концов, они станут превалирующими при планировании и вводе в эксплуатацию новых Веб-служб и увеличении пользователей Интернета. Веб-приложения становятся все более распространенными и все более сложными, играя, таким образом, основную роль в большинстве онлайновых проектов. Как и во всех системах, основанных на взаимодействии между клиентом и сервером, уязвимости Веб-приложений обычно возникают из-за некорректной обработки запросов клиента и/или недостаточной проверки входной информации со стороны разработчика.
В первой части данной лекции мы рассмотрим вопросы специфичные для тестирования и отладки Веб-приложений.
Будут рассмотрены принципы следующих подходов к тестированию Веб-приложений [1, 2]:
- функциональное тестирование ;
- тестирование пользовательского интерфейса ;
- тестирование удобства использования ;
- нагрузочное и стрессовое тестирование ;
- проверка ссылок и HTML-кода;
- тестирование безопасности.
Также будет приведен обзор средств автоматизации тестирования Веб-приложений.
С общими вопросами тестирования и верификации информационных систем предлагается ознакомиться в курсе Интернет Университета Информационных Технологий "Верификация программного обеспечения" [3].
Во второй части лекции будут рассмотрены подходы и инструментальные средства отладки CSS, а также отладки и профилирования JavaScript.
19.1.2. Подходы к функциональному тестированию Веб-приложений
Функциональное тестирование (functional testing) – процесс верификации соответствия функционирования продукта его начальным спецификациям [4]. Характерным примером может быть проверка того, что программа подсчета выплат по банковской ссуде выдает корректные выкладки на любые введенные сумму ссуды и срок ее возврата. Обычно подобные проверки проводятся вручную, иногда к этому подключаются конечные пользователи в качестве бета-тестеров. Однако программные системы становятся все сложнее, а комбинации различных входных параметров и поддерживаемых операционных систем нередко исчисляются десятками и сотнями.
Перечислим некоторые из методов функционального тестирования веб-приложений [5, 6]:
- Record & Play – основан на возможности средств автоматизации тестирования автоматически генерировать код.
- Functional Decomposition – в основе лежит разбиение всех компонент фреймворка по функциональному признаку на бизнес-функции (реализуют/проверяют бизнес-функциональность приложения), user-defined функции (вспомогательные функции, которые еще имеют привязку к тестируемому приложению или к конкретному проекту), утилиты (функции общего назначения, не привязанные к конкретному приложению, технологии, проекту).
- Data-driven – основан на том, что к некоторому тесту или группе тестов привязывается источник данных, и этот тест или набор тестов циклически выполняется для каждой записи из этого источника данных. Вполне может применяться в комбинации с другими подходами.
- Keyword-driven – представляет собой фактически движок для обработки посылаемых ему команд, а сами инструкции выносятся во внешний источник данных.
- Object-driven – основан на том, что основные ходовые части фреймворка реализованы в виде объектов, что позволяет собирать тесты по кирпичикам.
- Model-based – основан на том, что тестируемое приложение (или его части) описывается в виде некоторой поведенческой модели.
Самым распространенным является подход, называемый Capture & Playback (другие названия – Record & Playback, Capture & Replay) [6]. Суть этого подхода заключается в том, что сценарии тестирования создаются на основе работы пользователя с тестируемым приложением. Инструмент перехватывает и записывает действия пользователя, результат каждого действия также запоминается и служит эталоном для последующих проверок. При этом в большинстве инструментов, реализующих этот подход, воздействия (например, нажатие кнопки мыши) связываются не с координатами текущего положения мыши, а с объектами HTML-интерфейса (кнопки, поля ввода и т.д.), на которые происходит воздействие, и их атрибутами. При тестировании инструмент автоматически воспроизводит ранее записанные действия и сравнивает их результаты с эталонными, точность сравнения может настраиваться. Можно также добавлять дополнительные проверки – задавать условия на свойства объектов (цвет, расположение, размер и т.д.) или на функциональность приложения (содержимое сообщения и т.д.).
Основное достоинство этого подхода – простота освоения. Создавать тесты с помощью инструментов, реализующих данный подход, могут даже пользователи, не имеющие навыков программирования.
Вместе с тем, у подхода имеется ряд существенных недостатков. Для разработки тестов не предоставляется никакой автоматизации; фактически, инструмент записывает процесс ручного тестирования. Если в процессе записи теста обнаружена ошибка, то в большинстве случаев создать тест для последующего использования невозможно, пока ошибка не будет исправлена (инструмент должен запомнить правильный результат для проверки). При изменении тестируемого приложения набор тестов трудно поддерживать в актуальном состоянии, так как тесты для изменившихся частей приложения приходится записывать заново.
19.1.3. Тестирование пользовательского интерфейса
Часть программной системы, обеспечивающая работу интерфейса с пользователем – один из наиболее нетривиальных объектов для верификации [7]. Нетривиальность заключается в двояком восприятия термина "пользовательский интерфейс".
С одной стороны пользовательский интерфейс – часть программной системы. Соответственно, на пользовательский интерфейс пишутся функциональные и низкоуровневые требования, по которым затем составляются тест-требования и тест-планы. При этом, как правило, требования определяют реакцию системы на каждый ввод пользователя (при помощи клавиатуры, мыши или иного устройства ввода) и вид информационных сообщений системы, выводимых на экран, печатающее устройство или иное устройство вывода. При верификации таких требований речь идет о проверке функциональной полноты пользовательского интерфейса – насколько реализованные функции соответствует требованиям, корректно ли выводится информация на экран.
С другой стороны пользовательский интерфейс – "лицо" системы, и от его продуманности зависит эффективность работы пользователя с системой. Факторы, влияющие на эффективность работы, в меньшей степени поддаются формализации в виде конкретных требований к отдельным элементам, однако должны быть учтены в виде общих рекомендаций и принципов построения пользовательского интерфейса программной системы. Проверка интерфейса на эффективность человеко-машинного взаимодействия получила название проверки удобства использования (usability verification, в русскоязычной литературе в качестве перевода термина usability часто используют слово "практичность").
Функциональное тестирование пользовательского интерфейса состоит из пяти фаз [7]:
- анализ требований к пользовательскому интерфейсу;
- разработка тест-требований и тест-планов для проверки пользовательского интерфейса;
- выполнение тестовых примеров и сбор информации о выполнении тестов;
- определение полноты покрытия пользовательского интерфейса требованиями.
- составление отчетов о проблемах в случае несовпадения поведения системы и требований, либо в случае отсутствия требований на отдельные интерфейсные элементы.
Все эти фазы точно такие же, как и в случае тестирования любого другого компонента программной системы. Отличия заключаются в трактовке некоторых терминов в применении к пользовательскому интерфейсу и в особенностях автоматизированного сбора информации на каждой фазе.
Так, тест-планы для проверки пользовательского интерфейса, как правило, представляют собой сценарии, описывающие действия пользователя при работе с системой. Сценарии могут быть записаны либо на естественном языке, либо на формальном языке какой-либо системы автоматизации пользовательского интерфейса. Выполнение тестов при этом производится либо оператором в ручном режиме, либо системой, которая эмулирует поведение оператора.
При сборе информации о выполнении тестовых примеров, как правило, применяются технологии анализа выводимых на экран форм и их элементов (в случае графического интерфейса) или выводимого на экран текста (в случае текстового), а не проверка значений тех или иных переменных, устанавливаемых программной системой.
Под полнотой покрытия пользовательского интерфейса понимается то, что в результате выполнения всех тестовых примеров каждый интерфейсный элемент был использован хотя бы один раз во всех доступных режимах.
Отчеты о проблемах в пользовательском интерфейсе могут включать в себя как описания несоответствий требований и реального поведения системы, так и описания проблем в требованиях к пользовательскому интерфейсу. Основной источник проблем в этих требованиях – их тестонепригодность, вызванная расплывчатостью формулировок и неконкретностью.
Тестирование пользовательского интерфейса может проводиться различными методами – как вручную при непосредственном участии оператора, так и при помощи различного инструментария, автоматизирующего выполнение тестовых примеров. Рассмотрим эти методы более подробно.
19.1.3.1. Ручное тестирование
Ручное тестирование пользовательского интерфейса проводится тестировщиком-оператором, который руководствуется в своей работе описанием тестовых примеров в виде набора сценариев. Каждый сценарий включает в себя перечисление последовательности действий, которые должен выполнить оператор и описание важных для анализа результатов тестирования ответных реакций системы, отражаемых в пользовательском интерфейсе. Типичная форма записи сценария для проведения ручного тестирования – таблица, в которой в одной колонке описаны действия (шаги сценария ), в другой – ожидаемая реакция системы, а третья предназначена для записи того, совпала ли ожидаемая реакция системы с реальной и перечисления несовпадений.
В табл. 19.1 приведен пример сценария для ручного тестирования пользовательского интерфейса [7].
Ручное тестирование пользовательского интерфейса удобно тем, что контроль корректности интерфейса проводится человеком, т.е. основным "потребителем" данной части программной системы. К тому же при чисто косметических изменениях в интерфейсах системы, не отраженных в требованиях (например, при перемещении кнопок управления на 10 пикселей влево) анализ успешности прохождения теста будет выполняться не по формальным признакам, а согласно человеческому восприятию.
При этом ручное тестирование имеет и существенный недостаток – для его проведения требуются значительные человеческие и временные ресурсы. Особенно сильно этот недостаток проявляется при проведении регрессионного тестирования и вообще любого повторного тестирования – на каждой итерации повторного тестирования пользовательского интерфейса требуется участие тестировщика-оператора. В связи с этим в последнее десятилетие получили распространение средства автоматизации тестирования пользовательского интерфейса, снижающие нагрузку на тестировщика-оператора.
19.1.3.2. Сценарии на формальных языках
Естественный способ автоматизации тестирования пользовательского интерфейса – использование программных инструментов, эмулирующих поведение тестировщика-оператора при ручном тестировании пользовательского интерфейса.
Такие инструменты используют в качестве входной информации сценарии тестовых примеров, записанные на некотором формальном языке, операторы которого соответствуют действиям пользователя – вводу команд, перемещению курсора, активизации пунктов меню и других интерфейсных элементов.
При выполнении автоматизированного теста инструмент тестирования имитирует действия пользователя, описанные в сценарии, и анализирует интерфейсную реакцию системы. При этом для определения ожидаемого состояния пользовательского интерфейса могут использоваться различные методы – либо анализ снимков экрана и сравнение их с эталонными, либо доступ к данным интерфейсных элементов средствами операционной системы (например, доступ ко всем кнопкам окна по их дескрипторам и получение значений текста).
И при передаче информации в тестируемый интерфейс и при получении информации для анализа могут использоваться два способа доступа к элементам интерфейса [7]:
- позиционный, при котором доступ к элементу осуществляется при помощи задания его абсолютных (относительно экрана) или относительных (относительно окна) координат и размеров;
- по идентификатору, при котором доступ к элементу осуществляется при помощи получения интерфейсного элемента при помощи его уникального идентификатора в пределах окна.
При внесении изменений в пользовательский интерфейс при использовании первого метода в результате проведения регрессионного тестирования будет выявлено большое количество не прошедших тестов – достаточно изменения местоположения одного ключевого интерфейсного элемента, как все сценарии начнут работать неверно. Соответственно при таком методе автоматизации тестирования необходимо менять значительную часть сценариев в системе тестов при каждом изменении интерфейса системы. Такой метод автоматизации тестирования подходит для систем с устоявшимся и редко изменяемым интерфейсом.
Второй метод автоматизации тестирования более устойчив к изменению расположения интерфейсных элементов, но изменения тестовых примеров могут потребоваться и здесь в случае изменения логики работы интерфейсных элементов. Например, пусть в первой версии системы при нажатии на кнопку "Передать данные" передача данных начиналась сразу, и выводилось окно с индикатором прогресса. Сценарий тестового примера в этом случае включает в себя имитацию нажатия на кнопку и обращение к индикатору прогресса для получения значения прогресса в процентах.