Сайт о телевидении

Сайт о телевидении

» » Test policy — управление тестовой моделью. Современные технологии тестирования

Test policy — управление тестовой моделью. Современные технологии тестирования

18.09.2003 Александр Петренко, Елена Бритвина, Сергей Грошев, Александр Монахов, Ольга Петренко

Многие знают, как разработать программу; по крайней мере, каждый это делал много раз, но объяснить, как создать программу с высоким качеством, оказывается значительно труднее.

Индустрия программного обеспечения постоянно пытается решить вопрос качества, но насколько значимы ее успехи, на данный момент сказать довольно сложно. В статье идет речь о новом поколении инструментов тестирования, которые призваны повысить качество программ. Однако инструменты, даже автоматические, не в состоянии помочь, если их используют неправильно. Поэтому обсуждение инструментов предваряет изложение общих положений «правильного» тестирования.

Подходы к улучшению качества программ

«Борьба за качество» программ может вестись двумя путями. Первый путь «прост»: собрать команду хороших программистов с опытом участия в аналогичных проектах, дать им хорошо поставленную задачу, хорошие инструменты, создать хорошие условия работы. С большой вероятностью можно ожидать, что удастся разработать программную систему с хорошим качеством.

Второй путь не так прост, но позволяет получать качественные программные продукты и тогда, когда перечисленные условия соблюсти не удается - не хватает хороших программистов, четкости в поставке задачи и т.д. Этот путь предписывает стандартизировать процессы разработки: ввести единообразные требования к этапам работ, документации, организовать регулярные совещания, проводить инспекцию кода и проч. Одним из первых продвижений на этом фронте стало введение понятия жизненного цикла программной системы, четко определявшее необходимость рассмотрения многих задач, без решения которых нельзя рассчитывать на успех программного проекта.

В простейшем варианте набор этапов жизненного цикла таков:

  • анализ требований;
  • проектирование (предварительное и детальное);
  • кодирование и отладка ("программирование");
  • тестирование;
  • эксплуатация и сопровождение.

Стандартизованная схема жизненного цикла с четкой регламентацией необходимых работ и с перечнем соответствующей документации легла в основу так называемой «водопадной» или каскадной модели. Водопадная модель подразумевает жесткое разбиение процесса разработки программного обеспечения на этапы, причем переход с одного этапа на другой осуществляется только после того, как будут полностью завершены работы на предыдущем этапе. Каждый этап завершается выпуском полного комплекта документации, достаточной для того, чтобы разработка могла быть продолжена другой командой. Водопадная модель стала доминирующей в стандартах процессов разработки Министерства обороны США. Многие волей или неволей, даже отклоняясь от этой модели, в целом соглашались с ее разумностью и полезностью.

Водопадная модель требовала точно и полно сформулировать все требования; изменение требований было возможно только после завершения всех работ. Водопадная модель не давала ответ на вопрос, что делать, когда требования меняются или меняется понимание этих требований непосредственно во время разработки.

В конце 80-х годов была предложена так называемая спиральная модель, был развит и проверен на практике метод итеративной и инкрементальной разработки (Iterative and Incremental Development, IID). В спиральной модели были учтены проблемы водопадной модели. Главный упор в спиральной модели делается на итеративности процесса. Описаны опыты использования IID с длиной итерации всего в полдня. Каждая итерация завершается выдачей новой версии программного обеспечения. На каждой версии уточняются (и, возможно, меняются) требования к целевой системе и принимаются меры к тому, чтобы удовлетворить и новые требования. В целом Rational Unified Process (RUP) также следует этой модели.

Позволило ли это решить проблему качества? Лишь в некоторой степени.

Проблема повышения качества программного обеспечения в целом и повышения качества тестирования привлекает все большее внимание; в университетах вводят специальные дисциплины по тестированию и обеспечению качества, готовят узких специалистов по тестированию и инженеров по обеспечению качества. Однако по-прежнему ошибки обходятся только в США от 20 до 60 млрд. долл. ежегодно. При этом примерно 60% убытков ложится на плечи конечных пользователей. Складывается ситуация, при которой потребители вынуждены покупать заведомо бракованный товар.

Вместе с тем, ситуация не безнадежна. Исследование, проведенное Национальным институтом стандартов и технологии США, показало, что размер убытков, связанных со сбоями в программном обеспечении, можно уменьшить примерно на треть, если вложить дополнительные усилия в инфраструктуру тестирования, в частности, в разработку инструментов тестирования.

Каково же направление главного удара? Что предлагают «наилучшие практики»?

В 80-е и 90-е годы ответ на этот вопрос звучал примерно так. Наиболее дорогие ошибки совершаются на первых фазах жизненного цикла - это ошибки в определении требований, выборе архитектуры, высокоуровневом проектировании. Поэтому надо концентрироваться на поиске ошибок на всех фазах, включая самые ранние, не дожидаясь, пока они обнаружатся при тестировании уже готовой реализации. В целом тезис звучал так: «Сократить время между моментом?внесения? ошибки и моментом ее обнаружения». Тезис в целом хорош, однако не очень конструктивен, поскольку не дает прямых рекомендаций, как сокращать это время.

В последние годы в связи с появлением методов, которые принято обозначать эпитетом agile («шустрый», «проворный») предлагаются и внедряются новые конструктивные методы раннего обнаружения ошибок. Скажем, современные модели, такие как Microsoft Solutions Framework (MSF) и eXtreme Programming (XP), выделяют следующие рекомендации к разработке тестов:

  • все необходимые тесты должны быть готовы к моменту реализации той или иной части программы; при этом обычно один тест соответствует одному требованию;
  • совокупность ранее созданных тестов должна (при неизменных требованиях) выполняться на любой версии программы;
  • если же в требования вносятся изменения, то тесты должны меняться максимально оперативно.

Иными словами, ошибка - будь она в требованиях, в проекте или в реализации - не живет дольше момента запуска теста, проверяющего реализацию данного требования. Значит, хотя астрономическое время между «внесением» ошибки и ее обнаружением может оказаться и большим, но впустую усилий потрачено не очень много, реализация не успела уйти далеко.

Не будем останавливаться на справедливости этих положений и их эффективности. Как часто бывает, побочный эффект новшества оказался более значимым, чем собственно реализация этой идеи. В данном случае дискуссии вокруг «шустрых» методов привели к новому пониманию места тестирования в процессе разработки программного обеспечения. Оказалось, тестирование в широком понимании этого слова, т.е. разработка, пропуск тестов и анализ результатов, решают не только задачу поиска уже допущенных в программном коде ошибок. Серьезное отношение к тестированию позволяет предупреждать ошибки: стоит перед тем, как писать код, подумать о том, какие ошибки в нем можно было бы сделать, и написать тест, нацеленный на эти ошибки, как качество кода улучшается.

В новых моделях жизненного цикла тестирование как бы растворяется в других фазах разработки. Так, MSF не содержит фазы тестирования - тесты пишутся и используются всегда!

Итак, различные работы в процессе производства программ должны быть хорошо интегрированы с работами по тестированию. Соответственно, инструменты тестирования должны быть хорошо интегрированы со многими другими инструментами разработки. Из крупных производителей инструментов разработки программ, первыми это поняли компании Telelogic (набор инструментов для проектирования, моделирования, реализации и тестирования телекоммуникационного ПО, базирующийся на нотациях SDL/MSC/TTCN) и Rational Software (аналогичный набор, преимущественно базирующийся на нотации UML). Следующий шаг сделала компания IBM, начав интеграцию возможностей инструментов от Rational в среду разработки программ Eclipse.

Тезис XP - «Пиши тест перед реализацией» - хорош как лозунг, но в реальности столь же неконструктивен. Для крупных программных комплексов приходится разрабатывать тесты различного назначения: тесты модулей, интеграционные или компонентные тесты, системные тесты.

Три составляющие тестирования - экскурс в теорию

Модульному тестированию подвергаются небольшие модули (процедуры, классы и т.п.). При тестировании относительного небольшого модуля размером 100-1000 строк есть возможность проверить, если не все, то, по крайней мере, многие логические ветви в реализации, разные пути в графе зависимости данных, граничные значения параметров. В соответствии с этим строятся критерии тестового покрытия (покрыты все операторы, все логические ветви, все граничные точки и т.п.).

Проверка корректности всех модулей, к сожалению, не гарантирует корректности функционирования системы модулей. В литературе иногда рассматривается «классическая» модель неправильной организации тестирования системы модулей, часто называемая методом «большого скачка». Суть метода состоит в том, чтобы сначала оттестировать каждый модуль в отдельности, потом объединить их в систему и протестировать систему целиком. Для крупных систем это нереально. При таком подходе будет потрачено очень много времени на локализацию ошибок, а качество тестирования останется невысоким. Альтернатива «большому скачку» - интеграционное тестирование , когда система строится поэтапно, группы модулей добавляются постепенно.

Распространение компонентных технологий породило термин «компонентное тестирование» как частный случай интеграционного тестирования.

Полностью реализованный программный продукт подвергается системному тестированию . На данном этапе тестировщика интересует не корректность реализации отдельных процедур и методов, а вся программа в целом, как ее видит конечный пользователь. Основой для тестов служат общие требования к программе, включая не только корректность реализации функций, но и производительность, время отклика, устойчивость к сбоям, атакам, ошибкам пользователя и т.д. Для системного и компонентного тестирования используются специфические виды критериев тестового покрытия (например, покрыты ли все типовые сценарии работы, все сценарии с нештатными ситуациями, попарные композиции сценариев и проч.).

Инструменты тестирования - реальная практика

Закончив экскурс в методику, вернемся к вопросу, какие инструменты тестирования используются в настоящее время и насколько они соответствуют новым представлениям о месте тестирования в процессе разработки программ.

На данный момент в наибольшей мере автоматизированы следующие этапы работ: исполнение тестов, сбор полученных данных, анализ тестового покрытия (для модульного тестирования обычно собирают информацию о покрытых операторах и о покрытых логических ветвях), отслеживание статуса обработки запросов на исправление ошибок.

Обзор инструментов тестирования будем вести в обратном порядке - от системного тестирования к модульному.

Широко распространены инструменты тестирования приложений с графическим пользовательским интерфейсом. Их часто называют инструментами функционального тестирования . Если уровень ответственности приложения не велик, то таким тестированием можно ограничиться; подобное тестирование наиболее дешево.

В данном виде тестирования широко применяются инструменты записи-воспроизведения (record/playback); из наиболее известных продуктов можно назвать Rational Robot (компания IBM/Rational), WinRunner (Mercury Interactive), QARun (Compuware). Наряду с этим существуют инструменты для текстовых терминальных интерфейсов, например, QAHiperstation компании Compuware.

Для системного нагрузочного тестирования Web-приложений и других распределенных систем широко используется инструментарий LoadRunner от Mercury Interactive; он не нацелен на генерацию изощренных сценариев тестирования, зато дает богатый материал для анализа производительности, поиска узких мест, сказывающихся на производительности распределенной системы.

Примерная общая схема использования инструментов записи-воспроизведения такова:

  • придумать сценарий (желательно, на основе систематического анализа требований);
  • провести сеанс работы в соответствии с данным сценарием; инструмент запишет всю входную информацию, исходившую от пользователя (нажатия клавиш на клавиатуре, движения мыши и проч.), и сгенерирует соответствующий скрипт.

Полученный скрипт можно многократно запускать, внося в него при необходимости небольшие изменения.

При записи скрипта можно делать остановки для того, чтобы указывать, какие ответы системы в конкретной ситуации надо рассматривать как правильные, какие вариации входных данных пользователя возможны и т.д. При наличии таких вариаций при очередном воспроизведении теста инструмент самостоятельно будет выбирать одну из определенных альтернатив. При несовпадении ответа системы с ожидаемым ответом будет фиксироваться ошибка.

Впрочем, возможности данного вида тестирования ограничены:

  • запись скриптов возможна только при наличии прототипа будущего графического интерфейса;
  • поддержка скриптов очень трудоемка; часто скрипт легче записать заново, чем отредактировать;
  • как следствие, проводить работы по созданию тестов параллельно с разработкой самой системы не эффективно, а до создания прототипа вообще невозможно.

Следующий класс инструментов - инструменты тестирования компонентов . Примером является Test Architect (IBM/Rational). Такие инструменты помогают организовать тестирование приложений, построенных по одной из компонентных технологий (например, EJB). Предусматривается набор шаблонов для создания различных компонентов тестовой программы, в частности, тестов для модулей, сценариев, заглушек.

Отвечает ли этот инструмент требованию опережающей разработки тестов? В целом, да: для создания теста достаточно описания интерфейсов компонентов. Но есть и слабые места, которые, впрочем, присущи и большинству других инструментов. Так, сценарий тестирования приходится писать вручную. Кроме того, нет единой системы задания критериев тестового покрытия и связи этих критериев с функциональными требованиями к системе.

Последний из рассматриваемых здесь классов инструментов - инструменты тестирования модулей . Примером может служить Test RealTime (IBM/Rational), предназначенный для тестирования модулей на C++. Важной составляющей этого инструмента является механизм проверочных «утверждений» (assertion). При помощи утверждений можно сформулировать требования к входным и выходным данным функций/методов классов в форме логических условий, в аналогичной форме можно задавать инвариантные требования к данным объектов. Это существенный шаг вперед по сравнению с Test Architect. Аппарат утверждений позволяет систематическим образом представлять функциональные требования и на базе этих требований строить критерии тестового покрытия (правда, Test RealTime автоматизированной поддержки анализа покрытия не предоставляет).

В принципе, этим инструментом можно пользоваться при опережающей разработке тестов, но остается нереализованной все та же функция генерации собственно тестовых воздействий - эта работа должна выполняться вручную. Нет никакой технической и методической поддержки повторного использования тестов и утверждений.

Решение перечисленных проблем предлагает новое поколение инструментов, которые следуют подходу тестирования на основе модели (model based testing) или на основе спецификаций (specification based testing).

Чем могут помочь модели

В голове разработчика и тестировщика всегда присутствует та или иная «модель» устройства программы, а также «модель» ее желаемого поведения, исходя из которой, в частности, составляются списки проверяемых свойств и создаются соответствующие тестовые примеры. (Заметим, что это разные модели; первые часто называют архитектурными, а вторые - функциональными или поведенческими.) Они зачастую составляются на основе документов или обсуждений в неформальном виде.

Разработка моделей и спецификаций связана с «математизацией» программирования. Попытки использовать различные математические подходы для конструирования и даже генерации программ предпринимались с первых лет возникновения компьютеров. Относительный успех был достигнут в теории компиляторов, реляционных баз данных и в нескольких узкоспециальных областях; серьезных результатов в большинстве практических областей достичь не удалось. Многие стали относиться к формальным методам в программировании скептически.

Новый всплеск интереса к формальным методам произошел в первой половине 90-х. Его вызвали первые результаты, полученные при использовании формальных моделей и формальных спецификаций в тестировании.

Преимущества тестирования на основе моделей виделись в том, что:

  • тесты на основе спецификации функциональных требований более эффективны, так как они в большей степени нацелены на проверку функциональности, чем тесты, построенные только на знании реализации;
  • на основе формальных спецификаций можно создавать самопроверяющие (self-checking) тесты, так как из формальных спецификаций часто можно извлечь критерии проверки результатов целевой системы.

Однако не было ясности в отношении качества подобных тестов. Модели обычно проще реализации, поэтому можно было предположить, что тесты, хорошо «покрывающие» модель, слишком бедны для покрытия реальных систем. Требовались широкие эксперименты в реальных проектах.

Модель - некоторое отражение структуры и поведения системы. Модель может описываться в терминах состояния системы, входных воздействий на нее, конечных состояний, потоков данных и потоков управления, возвращаемых системой результатов и т.д. Для отражения разных аспектов системы применяются и различные наборы терминов. Формальная спецификация представляет собой законченное описание модели системы и требований к ее поведению в терминах того или иного формального метода. Для описания характеристик системы можно воспользоваться несколькими моделями в рамках нескольких формализмов. Обычно, чем более общей является нотация моделирования, тем больше трудностей возникает при автоматизации тестирования программы на основе модели/спецификации, описанной в этой нотации. Одни нотации и языки больше ориентированы на доступность и прозрачность описания, другие - на последующий анализ и трансляцию, в частности, трансляцию спецификации в тест. Предпринимались попытки разработки языка формальных спецификаций, удовлетворяющего требованиям промышленного использования (например, методология RAISE), однако широкого применения они не нашли.

Имеется несколько ставших уже классическими нотаций формальных спецификаций: VDM, Z, B, CCS, LOTOS и др. Некоторые из них, например, VDM, используются преимущественно для быстрого прототипирования. Язык B удобен для анализа, в частности для аналитической верификации моделей. Все эти языки активно используются в рамках университетских программ. В реальной практике для описания архитектурных моделей используется UML, а для построения поведенческих моделей - языки SDL/MSC, исполнимые диаграммы UML и близкие к ним нотации.

Перечисленные языки и нотации для поведенческих моделей, к сожалению, не обладают достаточной общностью. Они хорошо себя зарекомендовали в телекоммуникационных приложениях и практически бесполезны для описания функциональности программных систем «общего вида»: операционных систем, компиляторов, СУБД и т.д.

На роль инструментов разработки тестов для подобных систем претендует новое поколение средств описания моделей/спецификаций и средства генерации тестов на проверку согласованности поведения реализации заданной модели.

Инструменты тестирования на основе моделей

Test Real Time - один из первых представителей этой группы. Более широкие возможности предоставляет Jtest компании Parasoft. Интересен инструментарий компании Comformiq. Семейство инструментов разработки тестов на основе моделей предлагает Институт системного программирования РАН в кооперации с компанией ATS. Поскольку семейство UniTesK авторам знакомо существенно ближе, мы изложим общую схему подхода тестирования на основе моделей на примерах из UniTesK.

Рис. 1. Фазы процесса разработки спецификаций и тестов

Общая схема процесса разработки спецификаций и тестов состоит из четырех фаз (рис. 1).

Первая фаза относительно коротка, но в реальных проектах она важна. Именно здесь закладывается уровень абстрактности модели. Модель должна быть максимально простой: это позволит требовать исчерпывающего набора тестов. В то же время, модель должна быть содержательной, раскрывать специфику тестируемой реализации. Таким образом, задача первой фазы - найти компромисс между абстрактностью и детальностью.

Задача второй фазы - описание требований к поведению системы. Многие подходы (например, SDL) предлагают описывать исполнимые модели, которые можно рассматривать как прототипы будущей реализации. Задание требований в таком случае определяется формулой «реализация должна вести себя так же, как модель». Подход понятен, но, к сожалению, во многих реальных ситуациях он не работает. Допустим, в заголовке некоего сообщения, построенного моделью, указано одно время, а в аналогичном заголовке от реализации - несколько другое. Это ошибка или нет? Еще один пример. Модель системы управления памятью сгенерировала указатель на свободный участок памяти, а реальная система выдала другой указатель: модель и система работают в разных адресных пространствах. Ошибка ли это?

UniTesK - унифицированное решение

UniTesK предлагает использовать так называемые неявные спецификации или спецификации ограничений. Они задаются в виде пред- и постусловий процедур и инвариантных ограничений на типы данных. Этот механизм не позволяет описывать в модели алгоритмы вычисления ожидаемых значений функций, а только их свойства. Скажем, в случае системы управления памятью модель будет задана булевским выражением в постусловии типа «значение указателя принадлежит области свободной памяти». Простой пример постусловия для функции «корень квадратный» приведен на ; одна и та же спецификация представлена в трех разных нотациях: в стиле языков Cи, Java и C#. Использование спецификационных расширений обычных языков программирования вместо классических языков формальных спецификаций - шаг, на который идут почти все разработчики подобных инструментов. Их различает только выразительная мощность нотаций и возможности анализа и трансляции спецификаций.

Третья фаза - разработка тестового сценария. В простейшем случае сценарий можно написать вручную, но в данной группе инструментов - это плохой тон. Тест, т.е. последовательность вызовов операций целевой системы с соответствующими параметрами, можно сгенерировать, отталкиваясь от некоторого описания программы или структуры данных. Будем называть такое описание сценарием . Компания Conformiq предлагает описать конечный автомат. Различные состояния автомата соответствуют различным значениям переменных целевой системы, переходы - вызовам операций этой системы. Определить автомат - это значит для каждого состояния описать, в какое состояние мы перейдем из данного, если обратимся к любой наперед заданной операции с любыми наперед заданными параметрами. Если такое описание получить легко, больше ничего делать не понадобится: инструмент сгенерирует тест автоматически и представит результаты тестирования, например, в виде MSC-диаграмм. Но легко ли это, скажем, для программы с одной целочисленной переменной и двумя-тремя операциями? Скорее всего, да. Однако в общем случае сделать попросту невозможно.

В UniTesK для генерации тестовых последовательностей конечный автомат не описывается, а генерируется по мере исполнения теста. Все, что требуется от разработчика теста, - это задание способа вычисления состояния модели на основании состояния целевой системы и способа перебора применяемых в текущем состоянии тестовых воздействий. Эти вычисления записываются в тестовых сценариях. Очередное тестовое воздействие выбирается на основании спецификации сценария в зависимости от результатов предыдущих воздействий. Такой подход обладает двумя важными преимуществами. Во-первых, это позволяет строить сложные тестовые последовательности в чрезвычайно компактной и легкой для написания и понимания форме. Во-вторых, тесты приобретают высокую гибкость: они легко могут быть параметризованы в зависимости от текущих потребностей тестирования и даже могут автоматически подстраиваться под незначительные изменения модели. На рис. 3 приведен пример сценарного метода.

В целом тестовый сценарий описывает итераторы для всех методов данного класса, однако каждый раз разработчик теста решает только локальную проблему - как перебрать входные параметры одного-единственного метода. Общую задачу - как организовать последовательность вызов; как нужное число раз вернуться в одно и то же состояние, чтобы провести испытание еще для одного метода, еще для одного значения параметра; когда остановиться, чтобы не делать лишней работы - все это берет на себя инструмент.

В UniTesK используется единая архитектура тестов, подходящая для тестирования систем различной сложности, относящихся к разным предметным областям, и обеспечивающая масштабируемость тестов. Компоненты тестов, требующие написания человеком, отделены от библиотечных и генерируемых автоматически (рис. 4).

В реальных системах количество различимых состояний и количество допустимых в каждом из них тестовых воздействий очень велико, что приводит к комбинаторному «взрыву состояний». Для борьбы с этим эффектом разработан механизм факторизации модели: те состояния целевой системы, различие между которыми несущественно с точки зрения задач данного теста, объединяются в одно обобщенное состояние модели; аналогичным образом объединяются в группы и тестовые воздействия. Процесс факторизации предоставляет разработчику свободу творчества, но, вместе с тем, он поддержан строгими исследованиями, определяющими достаточные условия, при соблюдении которых гарантированы корректность результатов и существенное сокращение времени тестирования при сохранении достигаемого тестового покрытия.

Рис. 4. Архитектура тестовой программ

Создатели UniTesK, полагая, что не должно быть отдельной среды для разработки тестов, не только наделили его возможностью мимикрии под различные языки программирования, но обеспечили интеграцию составляющих его инструментов в популярные средства разработки программ. На рис. 5 представлен сеанс использования UniTesK в среде разработки Forte 4.0 компании Sun Microsystems.

Новое качество, которое обещают новые инструменты

Как отмечалось выше, создатели инструментов тестирования обычно сталкиваются со следующими проблемами:

  • отсутствие или нечеткость определения критериев тестового покрытия, отсутствие прямой связи с функциональными требованиями;
  • отсутствие поддержки повторного использования тестов;
  • отсутствие автоматической генерации собственно теста (это касается как входных воздействий, так и эталонных результатов или автоматических анализаторов корректности реализации).

Имеются ли у инструментов тестирования, которые для генерации теста используют модель или формальную спецификацию целевой системы, принципиальные преимущества перед традиционными средствами? Чтобы ответить на этот вопрос, укажем, как отмеченные проблемы решаются для инструментов, использующих модели.

Критерии тестового покрытия. Основной критерий - проверка всех утверждений, в частности, утверждений, определяющих постусловия процедур или методов. Он легко проверяется и легко связывается с функциональными требованиями к целевой системе. Так, инструменты UniTesK, инструменты для платформ Java и C# предоставляют четыре уровня вложенных критериев.

Повторное использование тестов. Уровень повторного использования существенно выше, чем у традиционных инструментов. Разработчик тестов пишет не тестовый скрипт, а критерии проверки утверждения и тестовый сценарий. И то, и другое лишено многих реализационных деталей, и поэтому их проще переиспользовать для новой версии целевой системы или для адаптации спецификаций и тестов для сходного проекта. Например, статистика UniTesK показывает, что уровень переиспользования для тестирования ядер разных операционных систем превышает 50%.

Автоматическая генерация тестов. Это главное достоинство новых инструментов; здесь они существенно опережают традиционные средства, поскольку используют не произвольные виды нотаций и методов моделирования и спецификации, а именно те, которые дают преимущества при автоматической генерации тестов. Так, утверждения позволяют сгенерировать тестовые «оракулы» - программы для автоматического анализа корректности результата; различные виды конечных автоматов или их аналоги позволяют сгенерировать тестовые последовательности. К тому же, поскольку модели обычно проще, чем реализации, для них удается провести более тщательный анализ, поэтому набор тестов становится более систематическим.

Рассмотренные инструменты опробованы на реальных, масштабных проектах. Конечно, каждый проект несет в себе некоторую специфику, возможно, препятствующую исчерпывающему тестированию. Однако опыт использования данных инструментов показывает, что обычно удается достичь хороших результатов, лучших, чем результаты, полученные в аналогичных проектах при помощи ручного тестирования. Пользователи UniTesK, обычно, за приемлемый уровень качества принимают 70-80% покрытия кода целевой системы; при этом должен быть удовлетворен, как минимум, критерий покрытия всех логических ветвей в постусловиях. Для некоторых сложных программ (в том числе, для блока оптимизации компилятора GCC) был достигнут уровень покрытия 90-95%.

Есть ли принципиальные ограничения в применимости данного подхода? Его практически невозможно применять в случае, когда по той или иной причине никто в цепочке заказчик - разработчик - тестировщик не смог или не захотел четко сформулировать требования к целевой системе. Впрочем, это не только ограничение, но и дополнительный стимул для улучшения процессов разработки, еще один повод объяснить заказчику, что вложения в фазу проектирования с лихвой окупаются сокращением общих сроков разработки и стоимости проекта.

Обозначения элементов общей структуры спецификации метода:

S - Сигнатура операции

A - Спецификация доступа

- Предусловие

B - Определение ветвей функциональности

> - Постусловие

Java:
Class SqrtSpecification { S Specification static double sqrt(double x) A reads x, epsilon { = 0; } post { > if(x == 0) { B branch «Zero argument»; > return sqrt == 0; > } else { B branch «Positive argument»; > return sqrt >= 0 && > Math.abs((sqrt*sqrt-x)/x) } } } }
Си:
S specification double SQRT(double x) A reads (double)x, epsilon { = 0.; } coverage ZP { if(x == 0) { B return(ZERO, «Zero argument»); } else { B return(POS, «Positive argument»); } } post { > if(coverage(ZP, ZERO)) { > return SQRT == 0.; > } else { > return SQRT >= 0. && > abs((SQRT*SQRT - x)/x) } } }
C#:
namespace Examples { specification class SqrtSpecification { S specification static double Sqrt(double x) A reads x, epsilon { = 0; } post { > if(x == 0) { B branch ZERO («Zero argument»); > return $this.Result == 0; > } else { B branch POS («Positive argument»); > return $this.Result >= 0 && > Math.Abs(($this.Result * $this.Result - x)/x) } > } > } } }

В главе вводится понятие качества, описывается технологический процесс тестирования и обсуждается связь качества и тестирования с различными технологическими процессами. Приводится традиционный взгляд на тестирование как на механизм оценки качества продукта, а также описывается, как на ранних этапах цикла разработки тестирование помогает усилить и упрочить архитектуру.

Цель

Целью тестирования является оценка качества продукта. Под этим подразумевается не только оценка окончательного продукта, но и оценка архитектуры с ранних этапов процесса и вплоть до окончательной передачи продукта раказчикам. включает следующее.

Проверку взаимодействий компонентов

Проверку правильности интеграции компонентов

Проверку точности реализации всех требований

Выявление дефектов и принятие мер, необходимых для их устранения до
развертывания программного обеспечения

Качество

Стандартное употребление термина качество включает в себя многое: как правило, этим словом обозначают отсутствие дефектов и (что гораздо важнее!) соответствие поставленной цели; с понятием качества мы связываем то, что нам нужно от продукта. В продукте (или его компоненте) могут отсутствовать дефекты, но если он не делает то, что необходимо нам, то он так же бесполезен, как и несовершенный продукт. Основной целью тестирования является оценка качества конечного продукта, а также оценка качества компонентов, составляющих его, и архитектуры, определяющей форму этих компонентов. Это нужно для того, чтобы убедиться, что продукт со-

Глава 12. Г67

ответствует определенным требованиям или превышает их (оценка производится согласно мерам и критериям приемлемости).

Качество продукта невозможно полностью оценить само по себе; программное обеспечение разрабатывается организацией с использованием технологического процесса, поэтому причиной плохого качества может стать некачественный процесс или процесс, которого трудно придерживаться. Как следствие, при оценке качества часто рассматривается не только качество самого продукта, но и организационные факторы и качество процесса.

Кто отвечает за качество продукта

За производство качественного продукта отвечают все члены проектной команды. Если качество не было изначально заложено в продукт, то его уже нельзя будет "добавить позднее" посредством выполнения некоторых активных действий, гарантирующих качество.

Задача тестирования - не гарантировать качество, а оценить его, одновременно обеспечивая обратную связь, позволяющую разрешить вопросы качества за разумную цену и в приемлемое время. Задача испытателя, выполняющего тестирование, - это оценивать качество и организовывать обратную связь, а задача проектной команды - создавать артефакты, удовлетворяющие требованиям и заданным параметрам качества.

Тестирование в итеративном жизненном цикле

Тестирование - это не обособленный вид деятельности и не фаза проекта, в которой выполняется оценка качества. Если разработчикам нужна своевременная обратная связь по вопросам качества продукта, то тестирование должно производиться в течение всего жизненного цикла: тестировать можно функциональные возможности ранних прототипов; устойчивость, охват и производительность архитектуры (при этом всегда можно подкорректировать неудачные решения); кроме того, можно протестировать конечный продукт и оценить его готовность к передаче в руки заказчиков. Существует распространенная точка зрения, что тестирование- это финальная проверка глобальной работоспособности; однако в данной ситуации упускается основное преимущество тестирования: возможность организации обратной связи, когда еще есть время (и ресурсы) для принятия необходимых мер.

Классификация тестов

Для оценки качества продукта требуются тесты различных типов. Для классификации тестов можно использовать следующие характеристики.

Тестируемый параметр качества - какой параметр качества проходит испытания

Этап тестирования- момент жизненного цикла, в котором выполняется
тестирование

Тип теста - конкретная задача отдельного теста, как правило, связанная с одним
параметром качества

Параметры качества

Существуют шаблоны, позволяющие выявить проблемы, связанные с качеством (как правило, практически во всех системах возникают однотипные проблемы). В результате для каждого продукта следует оценивать следующее.

Надежность

Программное обеспечение "сопротивляется" появлению ошибок в процессе выполнения: отсутствуют аварийные отказы, зависания, утечка памяти и т. п.

Функциональные возможности

Программное обеспечение реализует требуемые прецеденты или имеет ожидаемое поведение.

Я Производительность

Программное обеспечение и система работают, своевременно реагируют на предопределенные события и продолжают приемлемо функционировать в условиях реальных операционных характеристик (например, при значительной нагрузке, продолжительных периодах работы и т. д.). При тестировании производительности основное внимание уделяется обеспечению требуемых функциональных возможностей при удовлетворении нефункциональных требований системы.

Для каждого из указанных параметров качества требуется проведение одного или нескольких тестов на одном или нескольких этапах тестирования. Кроме того, существуют и другие параметры качества, оценка которых может быть более субъективной: удобство эксплуатации, расширяемость, гибкость и т.д. Качественную оценку этих параметров качества следует производить при каждой благоприятной возможности.

Этапы тестирования

Тестирование не следует считать обособленным видом деятельности, выполняемым целиком и сразу. Тестирование производится на разных этапах разработки программного обеспечения и направлено на проверку различных объектов (целевых объектов тестирования). Этапы тестирования прогрессируют - от тестирования небольших элементов системы, таких как компоненты (блочное тестирование), до тес- . тирования завершенных систем (системное тестирование). Перечислим существующие этапы тестирования и их задачи.

Блочное тестирование

Тестируются минимальные элементы системы. Время тестирования, как правило, совпадает со временем реализации элементов.

Интегральное тестирование

Тестируются интегральные блоки (или компоненты, или подсистемы).

Системное тестирование

Тестируются завершенные приложения и системы (состоящие из одного или нескольких приложений).

Приемочное тестирование

Конечными пользователями (или представителями конечных пользователей) тестируется завершенное приложение (или система). Цель тестирования: определить готовность к развертыванию продукта.

Следует помнить, что в разное время жизненного цикла этапы тестирования проходят с различными акцентами. Ранний концептуальный прототип, используемый в фазе исследования для оценки жизнеспособности видения продукта, будет подвергаться различным приемочным испытаниям. Архитектурный прототип, разрабатываемый в фазе уточнения плана, будет подвержен интегральным и системным испытаниям, направленным на проверку архитектурной целостности и производительности ключевых архитектурных элементов, несмотря на то что в это время большая часть кода системы имеет форму программ-суррогатов. Этапы тестирования - это не предопределенные "фазы", последовательно выполняемые ближе к концу проекта; наоборот, при итеративном жизненном цикле тестирование начинается рано и выполняется часто.

Типы тестов

Существует много типов тестов, каждый из которых акцентирует внимание на определенной задаче тестирования и тестирует только один параметр качества программного обеспечения. Поскольку тестирование производится в течение всего жизненного цикла, тестируемым программным обеспечением может быть отдельный фрагмент кода, интегральный блок или завершенное приложение (или система). Назовем наиболее распространенные типы тестов.

Аттестационный тест

Сравнивает производительность целевого объекта тестирования и некоторого стандартного объекта, например существующего программного обеспечения, или оценивает производительность согласно некоторой системе мер.

Конфигурационный тест

Проверяет приемлемость функционирования целевого объекта тестирования при различных конфигурациях (программных или аппаратных).

Функциональные испытания

Проверяется функционирование целевого объекта тестирования в общем, т.е. должная реализация требуемых прецедентов.

Установочные испытания

Проверяется правильность установки целевого объекта тестирования, возможность успешной установки при различных конфигурациях или в различных условиях (например, при недостатке дискового пространства).

Тестирование целостности

Проверяется надежность целевого объекта тестирования, его устойчивость и сопротивляемость ошибкам в процессе выполнения.

Испытание под нагрузкой

Проверяется приемлемость производительности целевого объекта тестирования в различных операционных условиях (включающих различное число пользователей, транзакций и т. д.) при неизменяемой конфигурации.

Эксплуатационные испытания

Проверяется приемлемость производительности целевого объекта тестирования в различных конфигурациях при постоянных операционных характеристиках.

Испытания в жестком режиме

Проверяется приемлемость производительности целевого объекта тестирования в аварийных или критических условиях, таких как ограниченные ресурсы или крайне большое число пользователей.

Регрессивное тестирование

Регрессивное тестирование - это методика испытаний, при которой тесты, производимые ранее, повторно выполняются на новой версии целевого объекта. Цель такого типа тестирования - обеспечить, чтобы качество целевого объекта не ухудшалось (не регрессировало) при добавлении к этому объекту новых функций. Регрессивное тестирование необходимо для

Максимально раннего выявления дефектов;

Проверки того, что изменения кода не приводят к новым дефектам или не
восстанавливают старые.

Регрессивное тестирование может включать повторное выполнение тестов любого типа. Как правило, такое тестирование выполняется в каждой итерации и состоит в повторном запуске тестов, произведенных при предыдущих итерациях.

Модель тестирования

Модель тестирования- это представление того, что будет тестироваться и как будет производиться тестирование. Эта модель является представлением моделей проектирования и реализации, изображающим собственно тесты и параметры целевых объектов, относящиеся к тестированию. Модель тестирования включает набор контрольных задач, методик испытания, сценариев испытаний и ожидаемых результатов тестирования, а также описание их взаимосвязи.

Рассмотрим подробнее составляющие модели тестирования.

Контрольные задачи

Набор тестовых данных, условий выполнения тестов и ожидаемых результатов, разработанный для конкретной задачи тестирования. Контрольные задачи могут определяться из прецедентов, проектной документации или программного кода. Контрольная задача может реализовываться с помощью одной или нескольких методик испытания.

Методики испытания

Набор подробных указаний по настройке и выполнению контрольных задач и оценке результатов, полученных при этом. С помощью одной методики испытаний может реализовываться одна или несколько контрольных задач. Методика испытаний также может использоваться для реализации только части контрольной задачи, например альтернативного потока прецедента.

Сценарии испытаний

Инструкции, автоматизирующие реализацию части или всей методики испытания (или методик испытания).

Классы и компоненты испытаний

Классы и компоненты, реализующие проекты тестов, в том числе драйверы и программы-суррогаты.

Взаимодействия тестов

Взаимодействия представляются в форме диаграммы взаимодействий или диаграммы последовательностей и отражают упорядоченный по времени поток сообщений между компонентами тестов и целевым объектом тестирования, имеющий место в процессе тестирования.

Примечания

Текстовая информация, описывающая ограничения, или дополнительная информация, используемая в модели тестирования. Примечания могут присоединяться к любому элементу модели тестирования.

Основные элементы модели тестирования и их взаимоотношения показаны на рис. 12.1.

Рис. 12.1. Контрольные задачи, методики испытаний и сценарии испытаний для банкомата

Исполнители и артефакты

В технологическом процессе тестирования задействованы два основных исполнителя.

Разработчик тестов отвечает за планирование, разработку, реализацию тестов и
оценку тестирования. В его обязанности входит создание плана и модели тести
рования, реализация методик испытания и оценка тестового покрытия, резуль
татов и эффективности теста.

Испытатель отвечает за выполнение системного тестирования. В его обязан
ности входит настройка и выполнение тестов, оценка выполнения теста, вос
становление после ошибок, оценка результатов тестирования и регистрация
выявленных дефектов.

Если для поддержки тестирования необходим специфический код (например, должны разрабатываться драйверы или программы-суррогаты), то в процессе должны участвовать еще разработчик и конструктор, исполняющие роли, подобные определенным в главах 10 и 11.

Исполнители и артефакты технологического процесса тестирования представлены на рис. 12.2. Давайте рассмотрим ключевые артефакты этого процесса.

План тестирования, содержащий информацию о целях и задачах тестирования.
План тестирования определяет, какие стратегии будут использоваться и какие
ресурсы требуются для выполнения тестирования.

Модель тестирования описывалась ранее.

Результаты тестирования и данные, собранные в процессе выполнения тестов.

Модель рабочей нагрузки для эксплуатационных испытаний; она определяет
переменные и их значения, используемые в различных эксплуатационных
испытаниях для моделирования или имитации характеристик внешних
исполнителей, функций, выполняемых конечными пользователями, объема
этих функций и нагрузки, создаваемой этими функциями.

Дефекты, полученные в результате "проваленных тестов" являются одним из
типов запросов на внесение изменений (см. главу 13).

Помимо перечисленных артефактов, при разработке программной поддержки теста должны создаваться следующие артефакты.

Пакеты и классы тестов

Подсистемы и компоненты тестов

Заключительная оценка тестов используется как часть оценки итерации проекта и периодической оценки состояния (см. главу 7, "Технологический процесс управления проектом").

Технологический процесс

Типичный технологический процесс тестирования, его основные элементы и зависимости между ними показаны на рис. 12.3.

Подготовка к тестированию

Целью этого элемента технологического процесса является определение и описание тестирования, которое будет выполняться. Для этого создается план тестирования, содержащий требования к тесту и стратегиям тестирования. Может разрабатываться единый план тестирования, в котором описаны все типы выполняемых тестов, или для каждого типа теста может создаваться отдельный план. Подготовка к тестированию выполняется таким образом, чтобы работы по тестированию были измеримыми и управляемыми.

Разработка теста

Целью этого элемента технологического процесса является определение, описание и создание модели тестирования и связанных с нею артефактов. Проект теста создается для того, чтобы убедиться в должной организации программного обеспечения, ис-пользуемого для тестирования, и в соответствии его заданным требованиям. При выполнении этого элемента технологического процесса разработчик тестов анализирует целевой объект тестирования, разрабатывает модель тестирования и (в случае эксплуатационных испытаний) модель рабочей нагрузки. Проект теста преобразовывает прецеденты в приемочные и системные контрольные задачи, которые затем направляют проектирование программных элементов, выполняющих тестирование.

Реализация теста

Цель этого элемента технологического процесса состоит в реализации методик испытания, определенных в разделе Подготовка к тестированию. Создание методик испытания производится, как правило, в среде средств автоматизации тестов или в среде программирования. Результирующим артефактом является электронная версия методики испытания, называемая сценарием испытания.

Если для поддержки или выполнения тестирования необходим специфический код (например, должны разрабатываться средства тестирования, драйверы или программы-суррогаты), то в работе по его созданию участвуют разработчик, конструктор и разработчик тестов.

Выполнение тестов на этапе интегрального тестирования

Цель этого элемента технологического процесса - обеспечение корректного объединения системных компонентов, а также проверка наличия у этого объединения правильного поведения. За компиляцию и объединение системы в увеличивающиеся функциональные блоки отвечает системный интегратор. Для каждого такого блока тестируются добавленные функции, выполняются регрессивные тесты и извлекаются результаты тестирования.

В ходе одной итерации интегральное тестирование выполняется несколько раз, пока не будет успешно интегрирована вся система (определяется целью итерации).

Выполнение тестов на этапе системного тестирования

Целью данного элемента технологического процесса является обеспечение должного функционирования всей системы. Системный интегратор компилирует и объединяет системы в увеличивающиеся функциональные блоки. Каждый добавляемый элемент

должен пройти тестирование функциональных возможностей; кроме того, выполняются все тесты, произведенные ранее над каждой конструкцией (регрессивные тесты).

В течение одной итерации системное тестирование выполняется несколько раз, пока не будет успешно интегрирована вся система (определяется целью итерации) и пока не будут удовлетворены критерии успеха тестирования или завершенности системы.

Оценка тестирования

Цель данного элемента технологического процесса - выработка и оценка количественных мер тестирования, позволяющих определить качество целевого объекта теста и процесса тестирования. Это выполняется посредством рецензирования и оценки результатов тестирования, определения и регистрации запросов на внесение изменений, а также вычисления основных мер теста.

Инструментальная поддержка

Поскольку тестирование - это итеративная работа, выполняемая в течение всего цикла разработки, инструментальная поддержка необходима для того, чтобы тестирование начать рано и выполнять часто; ручное тестирование недостаточно эффективно и не позволяет тщательно оценить разрабатываемое программное обеспечение. Последнее утверждение особенно справедливо для эксплуатационных испытаний и испытаний под нагрузкой, в которых должна моделироваться рабочая нагрузка и должен накапливаться значительный объем данных.

Корпорация Rational Software предлагает следующие инструментальные средства, поддерживающие автоматизацию тестов и процесс тестирования в целом.

TestStudio - это набор инструментальных средств, поддерживающих выполне
ние тестов и оценку результатов тестирования. Средства TestStudio позволяй
испытателю создавать сценарии тестирования, имеющие графический интер
фейс пользователя. Эти сценарии акцентируют внимание на таких параметра
качества, как надежность, функционирование и производительность. В набор
TestStudio входят следующие инструменты.

Robot поддерживает выполнение тестов, позволяя испытателям создавать и воспроизводить сценарии тестирования с графическим интерфейсом пользователя и сравнивать полученные и ожидаемые результаты.

LogViewer фиксирует результаты тестирования и представляет отчет для оценки выполнения теста.

TestManager поддерживает планирование, проектирование и оценку тестов, позволяет определить тестовое покрытие и генерирует отчеты о состоянии тестов.

TestFactory поддерживает тестирование надежности путем автоматического создания и выполнения сценариев тестирования. Кроме того, этот инструмент в программной форме сообщает о тестовом покрытии.

PerformanceStudio выполняет сценарии тестирования виртуального пользова
теля, используя для этого эксплуатационные испытания и некоторые функци
ональные испытания.

DevelopmentStudio поддерживает технологический процесс тестирования и
включает следующие инструментальные средства.

Rational Purify для локализации труднообнаруживаемых ошибок времени выполнения.

Rational PureCoverage* для определения участков кода, не прошедших тестирование, и выполнения анализа покрытия кода.

Rational Quantify* для выявления фрагментов кода, ограничивающих производительность.

Кроме того, для большинства из названных средств Rational Unified Process предлагает инструментальные наставники.

Резюме

Тестирование позволяет оценить качество производимого продукта.

Тестирование - это итеративный процесс, выполняемый во всех фазах жизнен
ного цикла; он позволяет рано организовать обратную связь по вопросам качест
ва, используемую для улучшения продукта в процессе его разработки и построе
ния. Тестирование должно выполняться не только в конце жизненного цикла
(для принятия или отклонения конечного продукта); оно должно быть неотъем
лемой частью механизма постоянной обратной связи.

За качество отвечают все. Качество не может вноситься тестирующей органи
зацией. Тестирование направлено только на оценку качества и организацию
своевременной обратной связи, позволяющей повысить качество системы.

Предлагает механизм обратной связи,
позволяющий измерять качество и определять дефекты. Тестирование выпол
няется на ранних стадиях проекта - начинается с планирования тестов и неко
торой оценки (иногда производимых даже в фазе исследования) и продол
жается по ходу реализации проекта.

Аннотация: Основные понятия тестирования. Фазы и этапы тестирования. Типы тестов. Разработка, управляемая тестами (Test Driven Development)

Введение

Тестирование является одним из наиболее устоявшихся способов обеспечения качества разработки программного обеспечения.

С технической точки зрения тестирование заключается в выполнении приложения на некотором множестве исходных данных и сверке получаемых результатов с заранее известными (эталонными) с целью установить соответствие различных свойств и характеристик приложения заказанным свойствам. Как одна из основных фаз процесса разработки программного продукта ( Дизайн приложения - Разработка кода - Тестирование), тестирование характеризуется достаточно большим вкладом в суммарную трудоемкость разработки продукта. Широко известна оценка распределения трудоемкости между фазами создания программного продукта: 40%-20%-40%.

С точки зрения математики тестирование можно рассматривать как интерпретацию некоторой формулы и проверки ее истинности на некоторых множествах. Действительно, программу можно представить в виде формулы f = f1* f2* f3*... * fn , где f1 , f 2 , ... fn - операторы языка программирования, а их суперпозиция - программа .

Обосновать истинность такой формулы можно при помощи формального подхода - то есть выводить из исходных формул-аксиом с помощью формальных процедур (правил вывода) искомые формулы и утверждения (теоремы). Преимущество формального подхода заключается в том, что с его помощью удается избегать обращений к бесконечной области значений и на каждом шаге доказательства оперировать только конечным множеством символов. Однако зачастую построение формальной системы и формализация самой программы являются очень сложными процессами. Альтернативным подходом обоснования истинности может служить интерпретация .

Интерпретационный подход применяется, когда осуществляется подстановка констант в формулы, а затем интерпретация формул как осмысленных утверждений в элементах множеств конкретных значений. Истинность интерпретируемых формул проверяется на конечных множествах возможных значений. Сложность подхода состоит в том, что часто число комбинаций значений очень велико и сами комбинации состоят из большого числа значений - а значит, обработка всех комбинаций потребует значительных ресурсов. Существуют различные методы, позволяющие уменьшить количество комбинаций, которые необходимо рассмотреть. Основная проблема тестирования - определение достаточности множества тестов для истинности вывода о правильности реализации программы, а также нахождения множества тестов, обладающих этим свойством.

Статическое тестирование выявляет формальными методами анализа без выполнения тестируемой программы неверные конструкции или неверные отношения объектов программы (ошибки формального задания) с помощью специальных инструментов контроля кода - CodeChecker.

Динамическое тестирование (собственно тестирование) осуществляет выявление ошибок только на выполняющейся программе с помощью специальных инструментов автоматизации тестирования - Testbed или Testbench.

Основы тестирования

Классы критериев тестирования

Структурные критерии используют информацию о структуре программы (критерии так называемого "белого ящика"), что предполагает знание исходного текста программы или спецификации программы в виде потокового графа управления. Структурные критерии базируются на основных элементах графа управления - операторах, ветвях и путях.

  • Условие критерия тестирования команд (критерий С0) - набор тестов в совокупности должен обеспечить прохождение каждой команды не менее одного раза.
  • Условие критерия тестирования ветвей (критерий С1) - набор тестов в совокупности должен обеспечить прохождение каждой ветви не менее одного раза.
  • Условие критерия тестирования путей (критерий С2) - набор тестов в совокупности должен обеспечить прохождение каждого пути не менее 1 раз.

Функциональные критерии формулируются в описании требований к программному изделию (критерии так называемого "черного ящика") Они обеспечивают, прежде всего, контроль степени выполнения требований заказчика в программном продукте. Поскольку требования формулируются к продукту в целом, они отражают взаимодействие тестируемого приложения с окружением. Проблема функционального тестирования - это прежде всего трудоемкость; дело в том, что документы, фиксирующие требования к программному изделию, как правило, достаточно объемны, тем не менее соответствующая проверка должна быть всеобъемлющей.

Выделяют следующие частные виды функциональных критериев :

  • тестирование пунктов спецификации;
  • тестирование классов входных данных;
  • тестирование правил - набор тестов в совокупности должен обеспечить проверку каждого правила, если входные и выходные значения описываются набором правил некоторой грамматики;
  • тестирование классов выходных данных;
  • тестирование функций;
  • комбинированные критерии для программ и спецификаций. Критерии стохастического тестирования формулируются в терминах

проверки наличия заданных свойств у тестируемого приложения, средствами проверки некоторой статистической гипотезы. Применяется при тестировании сложных программных комплексов - когда набор детерминированных тестов (X, Y) имеет громадную мощность.

Мутационные критерии ориентированы на проверку свойств программного изделия на основе подхода Монте-Карло.

Метод мутационного тестирования состоит в том, что в разрабатываемую программу P вносят мутации (мелкие ошибки), т.е. искусственно создают программы- мутанты P1, P2... . Затем программа P и ее мутанты тестируются на одном и том же наборе тестов (X, Y).

Если на наборе (X, Y) подтверждается правильность программы P и, кроме того, выявляются все внесенные в программы- мутанты ошибки, то набор тестов (X, Y) соответствует мутационному критерию, а тестируемая программа объявляется правильной. Если некоторые мутанты не выявили всех мутаций, то надо расширять набор тестов (X, Y) и продолжать тестирование.

Фазы тестирования

При тестировании как правило выделяют три фазы: модульное, интеграционное и системное тестирование.

Модульное тестирование - это тестирование программы на уровне отдельно взятых модулей, функций или классов. Цель модульного тестирования состоит в выявлении локализованных в модуле ошибок в реализации алгоритмов, а также в определении степени готовности системы к переходу на следующий уровень разработки и тестирования. Модульное тестирование проводится по принципу "белого ящика", то есть основывается на знании внутренней структуры программы, и часто включает те или иные методы анализа покрытия кода.

Интеграционное тестирование - это тестирование части системы, состоящей из двух и более модулей. Основная задача интеграционного тестирования - поиск дефектов, связанных с ошибками в реализации и интерпретации интерфейсного взаимодействия между модулями. Основная разница между модульным и интеграционным тестированиями состоит в целях, то есть в типах обнаруживаемых дефектов, которые, в свою очередь, определяют стратегию выбора входных данных и методов анализа.

Системное тестирование качественно отличается от интеграционного и модульного уровней. Оно рассматривает тестируемую систему в целом и оперирует на уровне пользовательских интерфейсов. Основная задача системного тестирования состоит в выявлении дефектов, связанных с работой системы в целом, таких как неверное использование ресурсов системы, непредусмотренные комбинации данных пользовательского уровня, несовместимость с окружением, непредусмотренные сценарии использования, отсутствующая или неверная функциональность, неудобство в применении и тому подобное.

Системное тестирование производится над проектом в целом с помощью метода "черного ящика". Структура программы не имеет никакого значения, для проверки доступны только входы и выходы, видимые пользователю. Тестированию подлежат коды и пользовательская документация.

Кроме того, выделяют регрессионное тестирование - цикл тестирования, который производится при внесении изменений на фазе системного тестирования или сопровождения продукта. Главная проблема регрессионного тестирования - выбор между полным и частичным перетестированием и пополнением тестовых наборов. При частичном перетестировании контролируются только те части проекта, которые связаны с измененными компонентами.

Этапы тестирования

Каждая фаза тестирования включает в себя следующие этапы:

  1. Определение целей (требований к тестированию), включающее следующую конкретизацию: какие части системы будут тестироваться, какие аспекты их работы будут выбраны для проверки, каково желаемое качество и т. п.
  2. Планирование : создание графика (расписания) разработки тестов для каждой тестируемой подсистемы; оценка необходимых человеческих, программных и аппаратных ресурсов; разработка расписания тестовых циклов . Важно отметить, что расписание тестирования обязательно должно быть согласовано с расписанием разработки создаваемой системы.
  3. Разработка тестов (тестового кода для тестируемой системы).
  4. Выполнение тестов : реализация тестовых циклов .
  5. Анализ результатов .

Тестовый цикл - это цикл исполнения тестов, включающий фазы 4 и 5 тестового процесса. Тестовый цикл заключается в прогоне разработанных тестов на некотором однозначно определяемом срезе системы (состоянии кода разрабатываемой системы). Обычно такой срез системы называют build .

Тестовый план - это документ, или набор документов, который содержит тестовые ресурсы, перечень функций и подсистем, подлежащих тестированию, тестовую стратегию , расписание тестовых циклов , фиксацию тестовой конфигурации (состава и конкретных параметров аппаратуры и программного окружения), определение списка тестовых метрик, которые на тестовом цикле необходимо собрать и проанализировать (например метрик, оценивающих степень покрытия тестами набора требований).

Тесты разрабатывают на основе спецификаций как вручную, так и с помощью автоматизирующих средств. Помимо собственно кода, в понятие "тест" включается его общее описание и подробное описание шагов, выполняемых в данном тесте.

Для оценки качества тестов используют различные метрики, связанные с количеством найденных дефектов, покрытием кода, функциональных требований, множества сценариев.

Вся информация об обнаруженных в процессе тестирования дефектах (тип, условия обнаружения , причина, условия исправления, время, затраченное на исправление) заносятся в базу дефектов.

Информация о тестовом плане , тестах и дефектах используется в конце каждого цикла тестирования для генерации тестового отчета и корректирования системы тестов для следующей итерации.

Типы тестов

В тестовом плане определяются и документируются различные типы тестов .

Типы тестирования по виду подсистемы или продукта таковы:

  1. Тестирование основной функциональности, когда тестированию подвергается собственно система, являющаяся основным выпускаемым продуктом.
  2. Тестирование инсталляции включает тестирование сценариев первичной инсталляции системы, сценариев повторной инсталляции (поверх уже существующей копии), тестирование деинсталляции, тестирование инсталляции в условиях наличия ошибок в инсталлируемом пакете, в окружении или в сценарии и т. п.
  3. Тестирование пользовательской документации включает проверку полноты и понятности описания правил и особенностей использования продукта, наличие описания всех сценариев и функциональности, синтаксис и грамматику языка, работоспособность примеров и т. п.

Типы тестирования по способу выбора входных значений:

  1. Функциональное тестирование, при котором проверяется:
    • покрытие функциональных требований;
    • покрытие сценариев использования.
  2. Стрессовое тестирование, при котором проверяются экстремальные режимы использования продукта.
  3. Тестирование граничных значений.
  4. Тестирование производительности.
  5. Тестирование на соответствие стандартам.
  6. Тестирование совместимости с другими программно-аппаратными комплексами.
  7. Тестирование работы с окружением.
  8. Тестирование работы на конкретной платформе.

Test Driven Development

Рассмотрим подход к тестированию, несколько отличающийся от приведенного выше. Разработка через тестирование ( Test Driven Development - TDD) - процесс разработки программного обеспечения, который предусматривает написание и автоматизацию модульных тестов еще до момента написания соответствующих классов или модулей. Это гарантирует, что все обязанности любого элемента программного обеспечения определяются еще до того, как они будут закодированы.

TDD задает следующий порядок этапов программирования:

  • Красный - напишите небольшой тест, который не работает, а возможно, даже не компилируется.
  • Зеленый - заставьте тест работать как можно быстрее, при этом не думайте о правильности дизайна и чистоте кода. Напишите ровно столько кода, чтобы тест сработал.
  • Рефакторинг - удалите из написанного вами кода любое дублирование.
  • Освоив TDD, разработчики обнаруживают, что они пишут значительно больше тестов, чем раньше, и двигаются вперед маленькими шагами, которые раньше могли показаться бессмысленными.

После того, как программист заставил тест работать и может быть уверен, что эта часть функциональности покрыта, он заставляет работать второй тест, затем третий, четвертый и т. д. Чем сложнее проблема, стоящая перед программистом, тем меньшую область функциональности должен покрывать каждый тест. В итоге получается 100% покрытие кода модульными тестами, чего, как правило, невозможно добиться при классическом подходе к тестированию.

Определенно существуют задачи, которые невозможно (по крайней мере на текущий момент) решить только при помощи тестов. В частности, TDD не позволяет механически продемонстрировать адекватность разработанного кода в области безопасности данных и взаимодействия между процессами. Безусловно, безопасность основана на коде, в котором не должно быть дефектов, однако она основана также на участии человека в процедурах защиты данных. Тонкие проблемы, возникающие в области взаимодействия между процессами, невозможно с уверенностью воспроизвести, просто запустив некоторый код.

Итоги

Чем активней разрабатываются новые информационные системы , усложняются архитектуры, развиваются новые технологии, тем важнее становится процесс тестирования. Появляется все больше сетевых приложений и приложений для мобильных устройств. Тестировать такие системы значительно сложнее, чем однопользовательские программы для домашних ПК. Для таких типов систем требуются эффективные алгоритмы автоматизации тестов. Кроме того, актуальна задача тестирования безопасности информационных систем во всех ее проявлениях. Индустрия видеоигр также нуждается в новых подходах к тестированию.

Тестирование сопровождает практически весь процесс разработки, включая самые ранние стадии. До сих пор необходимо улучшение технологий тестирования спецификаций и требований. Актуальна задача разработки тестов, тестирующих процесс разработки, требования бизнеса и цели всей организации. Речь идет о разработке более эффективных тестов, покрывающих самые различные характеристики информационной системы.

Кроме того, продолжаются исследования в области тестов, ориентированных на конкретную модель разработки (водопадную, спиральную) или на конкретную парадигму программирования. Например, для тестирования компонентно-ориентированных систем предлагается тестирование при помощи агентов. Для тестирования активных Java-апплетов предлагают использовать нейросети. Для тестирования агентов, существующих в web (роботы, пауки), предлагают использовать системы, основанные на знаниях.

Таким образом, несмотря на значительную определенность процесса тестирования и полную автоматизацию многих его этапов, остается масса направлений для исследований и практической работы.

Традиционный подход к автоматическим тестам выглядит примерно так - тестописатель изучает тестируемую систему и после этого руками пишет каждый отдельный сценарий для проверки искомой системы. Кто-то может написать тут гордое слово "handcrafted", а я называю это словом "handjob". А все потому, что обычно этот подход к созданию и написанию тестов страдает от двух проблем:

  • "Парадокс пестицида", описанный Борисом Бейзером в 1990-м году. Заключается он в том, что тесты все менее и менее эффективны в отлове багов, так как баги, для обнаружения которых эти тесты написаны, уже найдены и починены. Если же этого не происходит, то возникают серьезные вопросы к написанному коду и к рабочим процессам
  • Тесты статичны и их сложно менять, в то время как тестируемая система имеет свойство постоянно эволюционировать, обрастать новым функционалом и менять поведение старого. И тесты нужно менять каждый раз, когда функционал изменяет внешний вид программы или ее поведение. И с ростом сложности обновления тестов оправдывать чудовищные издержки на поддержку тестов становиться все сложнее.

Model-Based Testing данные проблемы практически полностью игнорирует, поскольку тесты создаются автоматически из точной модели приложения. Это сильно упрощает как поддержку уже существующих, так и генерацию новых, крайне полезных и гибких тестов.

Что такое модель?

Модель - это описание тестируемой системы. Формальная спецификация вполне сойдет. Модель должна быть сильно проще описываемой системы и как-то помогать нам понимать и предсказывать поведение тестируемого продукта.

Обычно в качестве модели используется или граф состояний или какой-нибудь конечный автомат. При этом граф состояний уже третий десяток лет используется в тестировании для представления тестируемого софта и дизайна тестов. Подробнее про эту технику дизайна тестов можно почитать . А лучше в целой куче книжек по тестированию, которые были выпущены за последние 25 лет.

Если вкратце, то можно описать так: тестируемое ПО начинает работу в каком-то состоянии ("главная страничка открыта"), принимает какой-то пользовательский ввод ("посмотреть фоточки котяток") и, в зависимости от этого ввода, переходит в новое состояние ("альбом с фоточками котяток появился"). Мы используем модели все время чтобы понять поведение того куска софта с которым работаем ("Хм... если я нахожусь тут и делаю вот это , то я окажусь вон там "). Да в общем-то все тестирование можно рассматривать как перемещение тестировщика через различные состояния системы и проверку того, что эти перемещения происходят корректно (что значит "корректно" это отдельная тема, так что пока мы ее пропустим).

Что такое Model-Based Testing?

Это довольно немолодая идея использовать формально описанные модели для того, чтобы сделать тестирование ПО более дешевым и простым занятием. Само Model-Based Testing это такая "продвинутая" техника тестирования через "черный ящик". У нее есть ряд бонусов перед традиционными методами:

  • Модель можно начинать собирать еще до того, как появятся первые строчки кода
  • Моделирование подразумевает основательную работу над спецификацией и архитектурой разрабатываемого ПО, что, как правило, позволяет на ранних этапах избавляться от фундаментальных проблем и банальных разночтений
  • Модель будет содержать информацию, которую можно будет переиспользовать в нуждах тестирования в будущем, даже если спецификация изменится
  • Модель сильно проще поддерживать, чем огромную кучу разрозненных тестов

И самое важное - формально описанные модели в комбинации с зачатками теории графов помогает легко и непринужденно генерировать сотни тестов.

Зоркий поклонник Agile может воскликнуть "эй! у нас есть BDD и оно покрывает первые три пункта и еще это спецификация!". Я же отвечу "нихрена подобного - ваши примеры станут нормальной спецификацией только тогда, когда короля Шака Зулу можно будет считать спецификацией на все человечество".

А теперь отбросим споры и посмотрим, как при помощи теории графов выбивать из модели то, что вам нужно для тестов.

Короткий ликбез по теории графов

Теория графов зародилась в 1736-м году в стареньком Прусском городе Кёнингсберге. Город стоял на двух берегах реки и попутно занимал еще и пару островов посреди этой самой реки. Жители этого города от безделья пытались придумать как посетить все семь мостов не проходя ни по одному дважды. Решали на практике, во время прогулок, и в теории, во время кухонных посиделок. Долгое время никто не мог доказать или опровергнуть возможность существования данного маршрута, пока не пришел зануда Эйлер и не испортил горожанам праздник.

Эйлер придумал изобразить каждый кусок суши как вершину графа, а мосты - ребрами графа.

И тут внезапно стало понятно, что нужного маршрута не существует. И все потому, что все вершины имеют нечетное число ребер. Ведь если у вершины четное число ребер, то гуляющий гражданин каждый раз заходя на этот кусок суши может выйти оттуда по новому мосту. Таким образом получается, что прогуляться по всем мостам не пересекая какой-то мост дважды не получится.

С тех пор граф, в котором все вершины имеют четное количество ребер называется "Эйлеровым Графом". А полный обход этого графа носит гордое имя "Эйлерова пути".

И после этого жителям Кёнингсберга пришлось найти себе другое развлечение. Только один китайский математик Мэй-Ку Куан все морочил себе голову этими мостами. А беспокоил его следующий вопрос:

Если нельзя построить маршрут так, чтобы каждый мост пересекался ровно один раз, то какое минимальное количество дополнительных пересечений моста нужно совершить для полного обхода.

А это уже сильно похоже на проблему, с которой встречаются почтальоны. Допустим, каждая вершина это почтовый ящик, куда нужно вкинуть писем. И, допустим, наш постальон должен вкинуть писем в каждый ящик не совершая лишних движений.

Куан предложил считать повторное пересечение моста добавлением еще одного ребра графа. Добавление ребер должно привести к тому, что у всех вершин графа будет четное количество ребер. Эту процедуру принято называть "Эйлеризацией" графа. И после того как граф "Эйлеризован" мы можем построить Эйлеров путь по нему.

И в честь Куана эту задачку назвали "задачей китайского почтальона".

Несколько лет спустя нашлись еще зануды, которым стало интересно что будет, если по ребрам графа можно будет ходить только в одну сторону. Как раз получается проблема, похожая на головную боль таксиста в Нью-Йорке, строящего маршрут по односторонним улочкам.

Тут мы введем еще один термин - орграф. Или ориентированный граф. Это такой граф, ребра которого можно пересекать только в указанном направлении. Направленные же ребра так же называются "дугами".

И если в случае Эйлерова Пути или Проблемы Китайского Почтальона мы оперировали дугами касающимися вершин, то тут приходится принимать во внимание еще и направление движения. И доля "Эйлеризации" такого графа нам требуется чтобы количество входящих в вершину дуг равнялось количеству исходящих. И считая каждую входящую дугу как "+1", а исходящую как "-1" мы можем вычислять "полярность" каждой вершины орграфа. Например вершина в двумя входящими и одной исходящей дугой имеет полярность "2 - 1 = 1".

Для того чтобы Эйлеризовать орграф нам нужно пририсовывать дуги между положительными и отрицательными вершинами. Это "выравнивание" числа входящих и исходящих дуг нам нужно для того же, для чего мы добивались четного числа ребер в неориентированном графе - любой посетитель вершины графа должен иметь возможность ее покинуть.

Причем тут тестирование?

Предположим, что у тестировщика есть модель поведения тестируемой системы. Так же предположим, что эта модель выглядит как диграф, где вершины представляют собой состояние системы, а дуги являются действиями, которые тестировщик может предпринять для изменения состояния системы.

Первое что захочет селать тестировщик - выполнить все возможные действия с тестируемой системой. Но как мы можем это выполнить эффективно? Тут сообразительному тестировщику в голову приходит задачка про таксиста из Нью-Йорка, которая просто слегка замаскировалась. И поскольку у нас уже есть модель тестируемой системы в виде графа, то нам нужно просто применить к ней подходящий алгоритм его обхода, который может быть сгенерирован автоматически.

С другой стороны, исполнение всех возможных действий это хорошо, но даже самый недалекий тест-менеджер понимает, что это банальное "покрытие состояний" в терминах тестирования сырого кода. Но у множителей есть одно неприятное свойство - у них, как правило, очень много "следующих" состояний у каждой вершины. Что же нам делать, если мы хотим проверить все возможные комбинации действий? Решения задач вроде задачи Китайского Почтальона не подходят, поскольку они гарантируют только посещение каждой дуги, но никак не посещение всех возможных комбинаций дуг.

Такой подход как раз активно использовался для тестирования конечных автоматов. К тому же это требование естественно вытекает из комбинаторной техники дизайна тестов под названием "все пары".

Решение предложил некий де Брюийн. Алгоритм выглядит примерно так:

  • Рисуем сбоку граф, где каждое ребро исходного графа является вершиной.
  • Там где у исходного графа дуга "1" входит в вершину, откуда выходит дуга "2" рисуем в свежеиспеченном графе дугу из вершины "1" в вершину "2".
  • Эйлеризуем полученный граф.
  • Рисуем Эйлеров путь на данном графе.

В принципе можно не напрягаться и просто сделать случайный обход графа. Что примечательно - такая стратегия достаточно устойчива к "парадоксу пестицида". С другой стороны, у любого мало-мальски сложного приложения довольно развесистый граф состояний, на которых можно потратить кучу времени, прежде чем получить хоть какое-то покрытие "случайным обходом".

Про то, зачем сюда добавляют Цепи Маркова, и как обычно решается распараллеливание таких тестов я напишу позже. А пока подведем краткие итоги.

Итого

Модели - это отличный способ представления и осмысления тестируемого приложения, но еще они дают нам довольно простой способ обновлять тесты и поспевать за постоянно эволюционирующим приложением.

Тестирование приложения мы можем рассматривать как обход графа, построенного на основе модели приложения. В свою очередь Теория Графов дает достаточный инструментарий для того, чтобы использовать информацию о поведении системы, описанную в модели, для генерации новых блестящих тестов.

И, поскольку Теория Графов позволяет нам работать непосредственно с моделью:

  • Новые обходы можно автоматически генерировать при изменении модели
  • Наши тесты могут легко и непринужденно меняться в рамках одной и той же модели
  • Различные алгоритмы обхода могут удовлетворять различным потребностям тестирования
  • Полученные алгоритмы обхода легко можно переиспользовать в совершенно новой среде

План курса:

1.
Тестовая модель и Как работать со структурой
2.
Как придумывать проверки
1.
2.
Техники тест-дизайна (Black-box)
Обзор техник White Box
3.
Работа с непротиворечивостью
4.
Формулирование проверок
5.
Приоритезация
6.
Соблюдение процесса работы с тестовой документацией

Аудит - Что проверяли

1.
Полнота покрытия (по требованиям)
2.
Непротиворечивость (дубликаты, противоречия требованиями)
3.
Структура (как делили на части и на тестовые наборы, как били на проверки)
4.
Содержимое проверок (формулировка, понятность всем участникам проекта)
5.
Оформление (описки, аккуратный внешний вид)
6.
Покрытие (Smoke/MAT/AT)
7.
Соблюдение процесса (процесс работы с тестовой документаций)

Ошибки для всех видов документации
Грамотность
60
10,4
Покрытие всех функций
проверками
42
9,4
Разбиение на функции
6,4
Внешний вид
6,2
Единый стиль
2,1
Методанные документа
2,1
Методанные результата
2
55
38
14
20
17
% от всех проектов
% от всех ошибок

Ошибки для Test Survey, Test Cases
Пропуск проверок
12,6
Ожидаемый
результат
Дубликаты
Единый стиль
Противоречия
Приоритет
70
47
6
38
3,5
25
2,4
25
1,6
1,4
19
% от всех проектов
% от всех ошибок

Тестовая модель

- это логическая структура, описывающая функциональность
системы и/или поведения пользователя, по которой
генерируются тест-кейсы. Построение тестовой модели
начинается с построения структуры, а затем утвержденная
структура наполняется тест-кейсами/проверками.
(с) Дмитрий Тищенко. Блог A1QA, 2014

Покрытие проверками

1) Актуальные хотелки клиента в спецификации\требованиях\макетах
2) Договоренности на проекте
3) Наличие необходимых проверок для каждой функции:
Техники тест-дизайна:




Equivalent Partitioning Testing
Boundary Values Testing
Pairwise testing
State transition Testing

Equivalence Partitioning

ТЕХНИКА ЭКВИВАЛЕНТНЫХ КЛАССОВ

*для простоты примера возьмем неизменную цену

1) Разбить на классы входные параметры

Параметр
Класс 1
Класс 2
Версия продукта
Standard
Premium
<0
0 <= количество < 100
Количество
Класс 3
>= 100
*Голос разума – для «Версии продукта» необходимо протестировать ВСЕ значения из класса валидных значений.
Н-р, для поля Оплаты (значения: картой, наличными, переводом) логично протестировать ВСЕ варианты отдельно

2) 1 класс == 1 проверка

Версия продукта
Case 1
Standard
Case 2
Premium
Кол-во

2) 1 класс == 1 проверка

Версия продукта
Case 1
Standard
Case 2
Premium
Кол-во
Case 3
-1
Case 4
16
Case 5
125

3) Негативная проверка только для 1го класса в кейсе

Версия продукта
Кол-во
Результат
Case 1
Standard
50
Positive
Case 2
Premium
50
Positive
Case 3
Standard
-1
Negative
Case 4
Standard
16
Positive
Case 5
Standard
125
Negative

4) Пересмотреть позитивные проверки

Версия продукта
Кол-во
Результат
Case 1
Standard
50
Positive
Case 2
Premium
50
Positive
Case 3
Standard
-1
Negative
Case 4
Standard
16
Positive
Case 5
Standard
125
Negative

5) Итого

Версия продукта
Кол-во
Результат
Case 1
Premium
50
Positive
Case 2
Standard
-1
Negative
Case 3
Standard
16
Positive
Case 4
Premium
125
Negative

Еще классы …

Параметр
Класс 1
Класс 2
Версия продукта
Standard
Premium
<0
0 <= Кол-во < 100
Дробные
Целые
Числа
Не числа
Кол-во
Класс 3
> 100
Пустое

Версия продукта
Кол-во
Результат
Case 1
Standard
50
Positive
Case 2
Premium
10
Positive
Case 3
Premium
-1
Negative
Case 4
Standard
16
Positive
Case 5
Premium
150
Negative
Case 6
Premium
19,45
Negative
Case 7
Premium
%Number!
Negative
Case 8
Standard
-
Negative

Версия продукта
Кол-во
Результат
Case 1
Standard
50
Positive
Case 2
Premium
10
Positive
Case 3
Premium
-1
Negative
Case 4
Standard
16
Positive
Case 5
Premium
150
Negative
Case 6
Premium
19.45
Negative
Case 7
Premium
%Number!
Negative
Case 8
Standard
-
Negative

~30% позитивных кейсов

Версия продукта
Кол-во
Результат
Case 1
Standard
50
Positive
Case 2
Premium
10
Positive
Case 3
Premium
-1
Negative
Case 4
Premium
150
Negative
Case 5
Premium
19.45
Negative
Case 6
Premium
%Number!
Negative
Case 7
Standard
-
Negative

Функция
Входной параметр
Получатель
Send
Тема
Тело
Файлы
Attach
Файлы
Форматирование Текст
Delete
Void
Класс 1
Класс 2
Существующий адрес Несуществующий адрес
Размер 0
0 < Размер <= Limit
Содержит символы @
._-+
Символы кроме @ . _ - +
Формат
Не формат
Размер 0
0 < Размер <= Limit
Содержит символы
кроме “∞₽₾₾©¥£µ®” Символы ∞₽₾₾©¥£µ®
Размер 0
0 < Размер <= Limit
Форматирование
Без форматирования
Нет
Один
Размер 0
0 < Размер <= Limit
Supported
Unsupported
Текст не выбран\не
выбирать
Текст
форматирование
Нажать
Класс 3
Размер > Limit
Размер > Limit
Размер > Limit
Много
Размер > Limit
Форматированн
ый текст


1
2
Получатель
Существует
0 < Размер <= Limit
Тема
0 < Размер <= Limit
Содержит символы
кроме “∞₽₾₾©¥£µ®”
3 Содержит символы @ . _ 0 < Размер <= Limit
-+
4 Формат
0 < Размер <= Limit
5 Несуществующий адрес 0 < Размер <= Limit
6 Размер 0
Содержит символы
кроме “∞₽₾₾©¥£µ®”
7 Размер > Limit
Содержит символы
кроме “∞₽₾₾©¥£µ®”
8 Не формат
0 < Размер <= Limit
9 0 < Размер <= Limit
Размер 0
10 0 < Размер <= Limit
Размер > Limit
11 0 < Размер <= Limit
Содержит символы
“∞₽₾₾©¥£µ®”
12 Существует
0 < Размер <= Limit
0 < Размер <= Limit
Formatting
Нет
Один
Ожидаемый
результат
Отправлено
Отправлено
0 < Размер <= Limit
Три
Отправлено
0 < Размер <= Limit
0 < Размер <= Limit
Formatting
Три
Нет
Один
Отправлено
Не доставлено
Не отправлено
Formatting
Один
Не отправлено
0 < Размер <= Limit
Formatting
0 < Размер <= Limit
0 < Размер <= Limit
Нет
Один
Три
Три
Не отправлено
Не отправлено
Не отправлено
Не отправлено
Размер > Limit
Нет
Не отправлено
Тело
Файлы

#
Входные
Результат
Void
Отмена удаления
Текст не выбран\не выбирать
форматирование
Письмо удалено
Письмо не удалено
Текст
Применено форматирование
4
Форматированный текст
Применено новое форматирование
5
Размер и формат из допустимых
значений
Файл прикреплен
Не указывать файл
Файл не прикреплен
Указать файл недопустимого размера
(min < или > max)
Файл не прикреплен
Указать неподдерживаемый файл
Файл не прикреплен
1
Функция
Удаление
2
3
6
7
8
Форматирование
Прикрепление
файла
Система не применяет форматирование

Boundary values

ТЕХНИКА ГРАНИЧНЫХ ЗНАЧЕНИЙ

Задача: Создать тест-кейсы для Evacuation Plan

Задача: Создать тест-кейсы для Evacuation Plan

0
Базовый Тест
Для успокоения нервов
Негативный Тест
99

99
0
0
99



Находим все пары (см. график)
В математике это Декартово произведение:
Evacuation_Plan х Risk_Assesment = {(a,b) | a ∈ Evacuation_Plan, b ∈ Risk_Assesment}
Evacuation_Plan х Risk_Assesment =
{ (-1,-1),
(-1,0), (-1,1),
(-1,50),
(-1,98), (-1,99), (-1,100),
(0,-1),
(0,0),
(0,1),
(0,50),
(0,98),
(0,99),
(0,100),
(1,-1),
(1,0),
(1,1),
(1,50),
(1,98),
(1,99),
(1,100),
(50,-1), (50,0), (50,1), (50,50),
(50,98), (50,99), (50,100),
(98,-1), (98,0), (98,1), (98,50),
(98,98), (98,99), (98,100),
(99,-1), (99,0), (99,1),
(99,50), (99,98), (99,99),
(99,100),
(100,-1), (100,0), (100,1), (100,50), (100,98), (100,99), (100,100),
}
7x7 = 49 проверок

Evacuation_Plan = {-1, 0, 1, 50, 98, 99, 100}
Risk_Assesment = {-1, 0, 1, 50, 98, 99, 100}
EP_Type = {Standard, Premium}
RA_Type = {Standard, Premium}
Количество кейсов = 7 * 7 * 2 * 2 = 196

Pairwise Testing

ТЕХНИКА ТЕСТИРОВАНИЯ ВСЕХ ПАР

Задача

Хранение данных (5): PostgreSQL, Oracle, MySQL, JSON, XML
Операционная система (4): Windows 7, 8, 10, OS X 10
RAM (3): 1 024 MB, 4 096 MB, 8 192 MB
HDD (2): SCSI, IDE
Полный перебор = 5 * 4 * 3 * 2 = 120 вариантов

Идеи

1. Протестировать пары значений, а не полные переборы
2. Эмпирическое доказательство эффективности
3. All Pairs/Orthogonal massive варианты техники

Работа с ортогональными
массивами

1
2
3
4
5
Data
PostgreSQL
Oracle
MySQL
JSON
XML
OS
Windows 7
Windows 8
Windows 10
OS X 10
RAM
1 024 MB
4 096 MB
8 192 MB
HDD
SCSI
IDE

Работа с ортогональными
массивами
1. Понять какие и сколько входных параметров:
1
2
3
4
5
Data
PostgreSQL
Oracle
MySQL
JSON
XML
OS
Windows 7
Windows 8
Windows 10
OS X 10
RAM
1 024 MB
4 096 MB
8 192 MB
HDD
SCSI
IDE

Работа с ортогональными
массивами
1. Понять какие и сколько входных параметров:
Хранение данных
OS
RAM
HDD
Column 5
Column 6
1
1
1
1
1
1
1
2
2
2
2
2
1
3
3
3
3
3
1
4
4
4
4
4
1
5
5
5
5
5
2
1
2
3
4
5
2
2
3
4
5
1
1
2
3
4
5
2
3
4
5
1
2
Data
PostgreSQL
Oracle
MySQL
JSON
XML
2
4
5
1
2
3
OS
Windows 7
Windows 8
Windows 10
OS X 10
2
5
1
2
3
4
3
1
3
5
2
4
RAM
1 024 MB
4 096 MB
8 192 MB
3
2
4
1
3
5
HDD
SCSI
IDE
3
3
5
2
4
1
3
4
1
3
5
2
3
5
2
4
1
3
4
1
4
2
5
3
4
2
5
3
1
4
4
3
1
4
2
5
4
4
2
5
3
1
4
5
3
1
4
2
5
1
5
4
3
2
5
2
1
5
4
3
5
3
2
1
5
4
5
4
3
2
1
5
5
5
4
3
2
1
2. Выбираем подходящий ортогональный массив – L25(56 ^6)

Работа с ортогональными
массивами
1. Понять какие и сколько входных параметров:
1
2
3
4
5
Data
PostgreSQL
Oracle
MySQL
JSON
XML
OS
Windows 7
Windows 8
Windows 10
OS X 10
RAM
1 024 MB
4 096 MB
8 192 MB
HDD
SCSI
IDE
2. Выбираем подходящий ортогональный массив –
3. Строим ортогональный массив
4. Удаляем ненужные КОЛОНКИ
L25(56 ^6)
Хранение данных
OS
RAM
HDD
1
1
1
1
1
2
2
2
1
3
3
3
1
4
4
4
1
5
5
5
2
1
2
3
2
2
3
4
2
3
4
5
2
4
5
1
2
5
1
2
3
1
3
5
3
2
4
1
3
3
5
2
3
4
1
3
3
5
2
4
4
1
4
2
4
2
5
3
4
3
1
4
4
4
2
5
4
5
3
1
5
1
5
4
5
2
1
5
5
3
2
1
5
4
3
2
5
5
4
3

Работа с ортогональными
массивами
1. Понять какие и сколько входных параметров:
Хранение данных
OS
RAM
HDD
1
PostgreSQL
Windows 7
1 024 MB
SCSI
2
PostgreSQL
Windows 8
4 096 MB
IDE
3
PostgreSQL
Windows 10
8 192 MB
SCSI
4
PostgreSQL
OS X 10
1 024 MB
SCSI
5
PostgreSQL
Windows 10
1 024 MB
SCSI
6
Oracle
Windows 7
4 096 MB
SCSI
7
Oracle
Windows 8
8 192 MB
SCSI
1
2
3
4
5
8
Oracle
Windows 10
1 024 MB
SCSI
Data
PostgreSQL
Oracle
MySQL
JSON
XML
9
Oracle
OS X 10
1 024 MB
SCSI
OS
Windows 7
Windows 8
Windows 10
OS X 10
10
Oracle
Windows 10
1 024 MB
IDE
11
MySQL
Windows 7
8 192 MB
SCSI
RAM
1 024 MB
4 096 MB
8 192 MB
12
MySQL
Windows 8
1 024 MB
SCSI
HDD
SCSI
IDE
13
MySQL
Windows 10
4 096 MB
IDE
14
MySQL
OS X 10
1 024 MB
SCSI
15
MySQL
OS X 10
4 096 MB
SCSI
16
JSON
Windows 7
4 096 MB
IDE
17
JSON
Windows 8
4 096 MB
SCSI
18
JSON
Windows 10
1 024 MB
SCSI
19
JSON
OS X 10
4 096 MB
SCSI
20
JSON
OS X 10
8 192 MB
SCSI
21
XML
Windows 7
4 096 MB
SCSI
22
XML
Windows 8
1 024 MB
SCSI
23
XML
Windows 10
4 096 MB
SCSI
24
XML
OS X 10
8 192 MB
IDE
25
XML
Windows 10
4 096 MB
SCSI
2. Выбираем подходящий ортогональный массив – L25(56 ^6)
3. Строим ортогональный массив
4. Удаляем ненужные КОЛОНКИ
5. Проставляем значения входных параметров
6. Заполняем пустые места + проверяем пары на релевантность

PICT
Хранение данных
OS
RAM
HDD
1
JSON
OSX_10
4096MB
SCSI
2
Oracle
Windows7
1024MB
IDE
3
MySQL
Windows10
8192MB
IDE
4
Oracle
Windows8
8192MB
SCSI
5
JSON
Windows8
1024MB
IDE
6
JSON
Windows7
8192MB
SCSI
7
Oracle
Windows10
1024MB
SCSI
8
XML
Windows7
4096MB
IDE
9
MySQL
OSX_10
1024MB
SCSI
10
JSON
Windows10
4096MB
SCSI
11
XML
Windows10
8192MB
SCSI
12
PostgreSQL
Windows8
4096MB
SCSI
13
MySQL
Windows7
4096MB
SCSI
14
XML
Windows8
1024MB
IDE
15
PostgreSQL
Windows7
1024MB
IDE
16
XML
OSX_10
8192MB
IDE
17
PostgreSQL
Windows10
8192MB
SCSI
18
MySQL
Windows8
4096MB
IDE
19
PostgreSQL
OSX_10
8192MB
IDE
20
Oracle
OSX_10
4096MB
SCSI

105*16*2*4*5*2 = 134 400

1
2
3
4
5

105
Subject
Arabic
Art History
Biology
Business
Studies
Chemistry

EAL
School level (16)
Elementary
Middle
High
School Wide
High/Middle

Likelihood
Definite
Tentative
Employment
Type
Full
Part
Substitute
Temporary
Contract length
1
2
3
4
Cover letter