Тестирование. Ю. Б. Попова тестирование и отладка программного
Скачать 0.6 Mb.
|
3.6. Особенности объектно-ориентированного тестирования С традиционной точки зрения в модульном тестировании наи- меньшим контролепригодным элементом является элемент или мо- дуль, который можно протестировать методом «белого ящика» [8]. При объектно-ориентированном тестировании этот функциональ- ный элемент не отделяется от своего класса, в котором он инкапсу- лирован со своими методами. Это означает, что поэлементное тес- тирование по существу заменяется классовым тестированием. Одна- ко не следует отклоняться слишком далеко от корневых принципов относительно того, что каждый метод класса можно рассматривать как «небольшой элемент», тестирование которого можно выполнять обособленно, применяя для этого методы «белого» и «черного» ящика. Объекты класса необходимо протестировать во всех воз- можных состояниях. Это означает, что необходимо сымитировать все события, вызывающие изменения состояния объекта. В традиционном отношении элементы компилируются в подсис- темы и подвергаются интеграционным тестам [8]. При объектно- ориентированном подходе не применяется тестирование структур- 23 ной схемы сверху вниз, поскольку точно не известно, какой класс будет вызван пользователем за предыдущим. Интеграционные тесты заменяются тестированием функциональных возможностей, при ко- тором тестируется набор классов, которые должны реагировать на один входной сигнал или системное событие, или же эксплуатацион- ным тестированием, при котором описывается один способ примене- ния системы, основанный на сценариях случаев эксплуатации. Тестирование взаимодействия объектов следует по путям сооб- щения с целью отследить последовательность взаимодействий объ- ектов, которая заканчивается только тогда, когда был вызван по- следний объект. При этом не посылается сообщение и не вызыва- ются службы любого другого объекта. Системное, альфа-, бета-тестирование и приемочное испытание пользователем изменяются незначительно, поскольку объектно- ориентированная система проходит эксплуатационные тесты точно так же, как и разработанные традиционным способом системы. Это означает, что процесс V&V по существу не изменяется. Тестирование классов охватывает виды деятельности, направ- ленные на проверку соответствия реализации этого класса специ- фикации. Если реализация корректна, то каждый экземпляр этого класса ведет себя подобающим образом. Тестирование классов в первом приближении аналогично тести- рованию модулей и может проводиться с помощью обзоров кода и выполнения тестовых случаев. Прежде чем приступать к тестированию класса, необходимо опре- делить, тестировать его в автономном режиме, как модуль, или ка- ким-то другим способом, как более крупный компонент системы. Для этого необходимо выяснить: – роль класса в системе, в частности, степень связанного с ним риска; – сложность класса, измеряемая количеством состояний, опера- ций и связей с другими классами; – объем трудозатрат, связанных с разработкой тестового драйве- ра для тестирования этого класса. Если какой-либо класс должен стать частью некоторой библио- теки классов, целесообразно выполнять всестороннее тестирование классов, даже если затраты на разработку тестового драйвера ока- жутся высокими. 24 При тестировании классов можно выделить 5 оцениваемых фак- торов [8]: 1. Кто выполняет тестирование. Как и при модульном тести- ровании, тестирование классов выполняет разработчик, поскольку он знаком со всеми подробностями программного кода. Основной недостаток того, что тестовые драйверы и программные коды раз- рабатываются одним и тем же персоналом, заключается в том, что неправильное понимание спецификации разработчиками распрост- раняется на тестовые наборы и тестовые драйверы. Проблем такого рода можно избежать путем привлечения независимых тестиров- щиков или других разработчиков для ревизий программных кодов. 2. Что тестировать. Тестировать нужно программный код на точное соответствие его требованиям, т. е. в классе должно быть реализовано все запланированное и ничего лишнего. Если для кон- кретного класса характерны статические элементы, то их также не- обходимо тестировать. Такие элементы принадлежат самому клас- су, но не каждому экземпляру. 3. Когда тестировать. Тестирование класса должно проводиться до того, как возникнет необходимость его использования. Необходи- мо также проводить регрессионное тестирование класса каждый раз, когда меняется его реализация. Однако до начала тестирования клас- са его необходимо закодировать и разработать тестовые случаи ис- пользования класса. Ранняя разработка тестовых случаев позволяет программисту лучше понять спецификацию класса и построить более успешную реализацию класса, которая пройдет все тестовые случаи. Существует даже практика первоначальной разработки тестовых слу- чаев, а затем программного кода. Такой подход направлен на изна- чально все предусматривающий программный код и носит название разработка через тестирование (англ., Test-Driven Development, TDD). Главное, чтобы этот подход не привел к проблемам во время инте- грации этого класса в более крупную часть системы. 4. Каким образом тестировать. Тестирование классов обычно выполняется путем разработки тестового драйвера. Тестовый драй- вер создает экземпляры классов и окружает их соответствующей средой, чтобы стал возможен прогон соответствующего тестового случая. Драйвер посылает одно или большее количество сообщений экземпляру класса (в соответствии с тестовым случаем), затем сверя- ет результат его работы с ожидаемым и составляет протокол о про- 25 хождении или не прохождении теста. В обязанности тестового драй- вера обычно входит и удаление созданного им экземпляра. 5. В каких объемах тестировать. Адекватность может быть из- мерена полнотой охвата тестами спецификации и реализации клас- са, т. е. необходимо тестировать операции и переходы состояний в различных сочетаниях. Поскольку объекты находятся в одном из возможных состояний, эти состояния определяют значимость операций. Поэтому требуется определить, целесообразно ли прово- дить исчерпывающее тестирование. Если нет, то рекомендуется вы- полнить наиболее важные тестовые случаи, а менее важные выпол- нять выборочно. 3.7. Автоматизация модульного тестирования Автоматизация модульного тестирования направлена за замену ручного запуска модульных тестов некоторым инструментальным средством. Для автоматизации модульного тестирования существу- ет достаточно большое количество инструментов (их принято назы- вать фреймворками), которое можно разделить на 3 группы: – семейство xUnit; – встроенные фреймворки в среды разработок; – универсальные инструменты для разных видов тестирования. 3.7.1. Семейство хUnit Семейство хUnit – это набор программных средств для разработ- ки модульных тестов, позволяющий реализовать построение тестов, их выполнение и вывод полученных результатов. Семейство хUnit имеет отдельную реализацию для большинства используемых в на- стоящее время языков программирования, например: – JUnit – для тестирования Java-кода; – DUnit – для тестирования программ на Delphi; – сppUnit – для тестирования с++ программ; – NUnit – для тестирования .NET приложений; – PyUnit – для тестирования программ, написанных на Python; – VBUnit – для программ, написанных на VisualBasic; – utPLSQL – для языка PLSQL (Oracle). 26 Также существует инструмент httpUnit, который реализован на языке Java и имеет следующие возможности: эмулирует основное поведение браузера, включая заполнения веб-форм, работу с элемен- тами JavaScript, основную http-аутентификацию, автоматическую страничную переадресацию, поддерживает работу с cookies, позво- ляет тестовому коду проверить возвращаемую страницу в виде html-текста с контейнерами форм, таблиц и линков. Используя воз- можности классов JUnit, позволяет легко создавать тестовые сцена- рии и быстро проводить автоматизированное тестирование функци- ональности веб-приложения. Инструмент httpUnit позволяет работать напрямую с веб-сервером без участия веб-браузера, заменяя его со- бой (рис. 3.3–3.4). Рис. 3.3. Схема работы веб-приложения Рис. 3.4. Схема работы инструмента httpUnit К преимуществам httpUnit можно отнести следующие: – высокая скорость работы скриптов, а также их работа в фоно- вом режиме, поскольку отсутствует посредник в виде браузера; – тестирование «чистого» приложения без учета особенностей браузера; – бесплатность, поскольку httpUnit является свободно распрост- раняемым инструментом автоматизации тестирования. 27 Основные классы httpUnit приведены в табл. 3.1. Таблица 3.1 Основные классы httpUnit Название класса Назначение класса WebConversation Основной класс HttpUnit. В объектах этого класса хранится информация о сессии браузера, которая возвращается сервером в виде cookies. Для работы с веб-сервером разработчик должен создать запрос и обратиться к WebConversation за ответом. Таким образом, WebConversation имитирует основное взаи- модействие пользовательского браузера с веб-прило- жением, а объект хранит последовательность посы- лаемых на веб-сервер запросов и возвращаемых в от- вет откликов с текстом веб-страниц. WebRequest Представляет собой http-запрос, посылаемый веб-сер- веру приложения. Объект WebRequest хранит всю не- обходимую информацию, которая должна содержать- ся в http-запросе, а именно: url, parameters, наборы символов. WebResponse Представляет собой http-отклик, возвращаемый веб- сервером приложения. Объект WebResponse хранит информацию о http-отклике, полученном по опреде- ленному http-запросу, а именно: тело отклика, наборы символов, исходный код и тип контекста html-стра- ницы. WebResponse предоставляет набор методов для получения отдельных частей исходного кода веб-стра- ницы в разобранном и структурированном виде. WebForm Представляет собой html-форму, содержит набор ме- тодов для чтения и записи данных из различных по- лей веб-форм, а также для утверждения формы. WebTable Представляет собой html-таблицу, содержит набор методов для чтения и записи данных из различных ячеек веб-таблицы, получения количества строк и столбцов таблицы и т. д. WebLink Представляет собой html-ссылку (линк), содержит всю информацию об определенной веб-ссылке: url, para- meters и текст ссылки. Объект WebLink позволяет имитировать нажатие на веб-ссылку левой клавишей мыши и переход на новую веб-страницу по необхо- димому адресу. 28 Пример: Поскольку класс WebConversation ответственен за поддержание соединения с сервером, то для его использования необходимо со- здать запрос, а затем опрашивать объект WebConversation: WebConversation wc = new WebConversation(); WebRequest req = new GetMethodWebRequest(“URL”); WEbResponse res = wc.GetResponse(req); Ответом (response) можно манипулировать как простым текстом, используя, например, GetTextMethod() или как объектом DOM, ис- пользуя GetDOMMethod(), или пользуясь другими методами. 3.7.2. Встроенные инструменты для автоматизации модульного тестирования Самым распространенным встроенным инструментом является MSTest, который интегрирован в MS Visual Studio, и предназначен для тестирования программных модулей, реализованных в этой среде. Проведем сравнительный анализ инструментов NUnit и MSTest для модульного тестирования. В табл. 3.2 приведена последова- тельность действий для создания тестов с использованием каждого из рассматриваемых инструментов, а в табл. 3.3 – названия атрибу- тов для пометок модульных тестов. Таблица 3.2 Последовательность действий для создания тестов в NUnit и MSTest NUnit MSTest Скачать библиотеку NUnit, подклю- чить ее к проекту, создать класс для написания в нем тестов. Создать тес- товые методы и пометить их с по- мощью специальных атрибутов. Для тестируемых методов создать тесто- вые заглушки. Использовать версию MS Visual Studio с интегрированным в нее мо- дулем UnitTest. Для создания теста для определенного метода щелкнуть по нему правой кнопкой мыши и вы- брать Сreate Unit Test. После добав- ления нового тестового проекта MS Visual Studio создаст класс с тесто- выми методами для отмеченных тес- тируемых методов. 29 Таблица 3.3 Таблица атрибутов NUnit и MSTest Название NUnit MSTests Атрибут для тестового класса TestFixture TestClass Атрибут для тестового метода Test TestMethod Атрибут для метода, выполняю- щегося перед всеми тестами TestFixtureSetUp ClassInitialize Атрибут для метода, выполняю- щегося после всех тестов TestFixtureTearDown ClassCleanUp Атрибут для метода, выполняю- щегося перед каждым тестом TearUp TestInitialize Атрибут для метода, выполняю- щегося после каждого теста TearDown TestCleanUp К недостаткам инструмента NUnit принято относить отсутствие generic методов (вместо них используются перегрузки), невозмож- ность тестировать свойства классов, необходимость создания заглу- шек для тестирования методов с типом доступа private. Преимуще- ством NUnit является его бесплатное распространение. К недостаткам MSTests относят его высокую стоимость в составе среды разработки MS Visual Studio, а из преимуществ отмечают удобство создания тестов вследствие отсутствия необходимости со- здавать классы и методы для них вручную. Анализ двух инструментов показывает, что их возможности прак- тически идентичны, последовательность действий для создания тес- тов однотипна, поэтому каждый вправе выбирать инструмент по своему усмотрению. 3.7.3. Использование универсальных инструментов автоматизации тестирования Самым популярным инструментом для проведения различных видов автоматизированного тестирования является TestComplete. Автоматизация модульного тестирования является лишь неболь- шой частью его возможностей, которую можно реализовать двумя способами: 30 1) Подключение тестов, ранее написанных в других средах, на- пример, в MSTest либо NUnit. Для запуска таких тестов существует два варианта: – вариант 1 – указать в настройках TestComplete расположение этого стороннего теста (Tools OptionsUnitTesting), создать про- ект для модульного тестирования, указав, что тесты были созданы в другом инструменте. Далее подключаем ранее созданные биб- лиотеки dll, содержащие тесты. При таком варианте инструменту TestComplete отводится роль средства по обработке, сбору и пред- ставлению результатов в удобной форме; – вариант 2 – в исходном тестовом инструменте подключить библиотеку AutomatedQA.TestComplete.UnitTesting.dll, указать, ка- кие классы будут видимы для TestComplete. Затем производится создание и настройка проекта в TestComplete и далее запуск тестов. На панели справа можно выбрать запуск всех тестов либо только выбранных. При таком варианте TestComplete принимает непосред- ственное участие в запуске тестов и обработке результатов, причем процесс происходит несколько быстрее. 2) Непосредственное создание модульных тестов в TestComplete. Для этого необходимо реализовать следующие этапы: a) Создание проекта. В TestComplete в окне Сreate New Project указывается имя, расположение и скриптовый язык будущего тес- тового проекта. В открывшемся окне Project Wizard можно указать, какие элементы проекта будут в него включаться (скрипты, список тестируемых приложений и т. д.). После нажатия кнопки Finish, TestComplete создаёт новый проект и отображает его содержимое в панели Project Explorer. b) Подготовка модульных тестов. TestComplete может видеть внутренние объекты тестируемого приложения и позволяет исполь- зовать три варианта написания тестов: – вариант 1 – создать метод, который тестирует остальные ме- тоды класса. Такой вариант реализуем, поскольку TestComplete мо- жет вызывать функции и методы непосредственно из кода прило- жения и обрабатывать исключения, которые случаются при непра- вильной работе тестируемого метода. В итоге не придется писать дополнительные тестовые классы; – вариант 2 – создать функцию, которая будет тестировать ме- тоды класса и генерировать исключение при ошибке. Функция до- 31 бавляется в тот же класс, где содержатся методы. Преимущества данного метода: количество классов в проекте не изменяется, функ- ция имеет доступ к методам с модификаторами private и protected; – вариант 3 – это создание отдельного класса для тестирования исходного класса. Преимущества: тестируемый и тестирующий клас- сы разделены, что дает возможность легко деактивировать модули, которые содержат тесты. с) Подготовка тестируемого приложения. Для этого необходимо открыть тестируемый проект, в разделе Bin/Extentions добавить ссылку на AutomatedQA.TestComplete.UnitTesting.dll, установить свойство CopyLocal = True. Затем необходимо вызвать метод AddClasses(), принадлежащий объекту UnitTesting, например, в сле- дующей реализации: Using TestComplete; Type[] types = {typeof(MyTestClass)}; UnitTesting.AddClasses(types); После добавления классов все методы, принадлежащие им, будут видны для TestComplete. Затем необходимо скомпилировать прило- жение и запустить его. d) Загрузка тестов. В созданный проект TestComplete необходи- мо добавить тестируемое приложение (Tested Аpplications Add New Item), которое должно быть запущено. Добавить объект TCUnitTest в раздел UnitTesting. В появившемся окне выбрать про- цесс, соответствующий тестируемому приложению. Загрузить дос- тупные тесты, выбрав для этого Menu->Mode->Load. Если был выб- ран автоматический режим, то тесты будут загружены автоматически. e) Запуск тестов. Для удобства запуска тестов можно добавить несколько строк кода в модуль Script, в результате чего TestComplete будет автоматически запускать тестируемое приложение и прогонять доступные тесты. Результаты каждого прогона модульных тестов сохраняются в UnitTesting логах и могут быть открыты для анализа. |