Архив автора: alexey

Тестирование программных продуктов. Белый ящик

Здесь становится понятна большая приспособленность термина "стеклянный ящик". Тестирование подобным способом происходит, в основном, сразу после написания тестируемого кода. Это, если хотите, правило хорошего тона в программировании. При объектно-ориентированном подходе, данная схема выглядит предпочтительной, т.к. позволяет абстрагироваться от окружения и тестировать отдельные сущности программы. Строго говоря, абстрагироваться от окружения позволяет не столько сам метод, сколько применяемые технологии. Здесь стоит упомянуть о методе, называемом "модульное тестирование".
Модульное тестирование применяется, если структура приложение позволяет условно разделить его на модули — отдельные целостные элементы. Данные модули могут представлять собой как отдельные классы, так и отдельные библиотеки классов. Конкретный подход к тестированию определяется внутри компании на основе данных о структуре приложения, среды написания, имеющихся технических и людских ресурсов определенного качества, а также сложившимися историческими предпочтениями. Не смотря на широкую вариативность разбиения общей структуры приложения на модули, существует общая особенность, присущая таким выделенным элементам. Это — интерфейс. Интерфейс модуля есть совокупность каналов с ограничениями, предназначенных для общения с внешним миром. В классах, например, роль интерфейса могут выполнять публичные методы. Учитывая эти факты, можно спрогнозировать потенциальные проблемы при модульной стратегии тестирования. Основная проблема заключается в следующем. Ценность модуля, как элемента приложения, проявляется лишь в момент работы внутри остальных элементов, составляющих вместе с рассматриваемым цельное приложение. Как быть в случае, если интеграция тестируемого (тут необходимо держать в голове презумпцию нестабильности еще не оттестированного модуля) элемента в общую систему слишком дорогое "удовольствие", либо окружение для него еще вообще не разработано? В этом случае применяют технологию заглушек. Для тестируемого модуля, создается искусственное окружение, эмулирующее работу реального. В качестве бытового аналога можно рассмотреть ситуацию с "фальшивым рулем" в автошколе. Для того чтобы научить человека пользоваться рулем, не обязательно создавать специально для него автомобиль. Можно обойтись "малой кровью", предоставив ему интерфейс — "фальшивый руль", прикрученный к столу. Используя его можно "оттестировать" насколько ловко обучаемый владеет искусством маневрирования.
После того, как отдельные модули были оттестированны, необходимо проверить, насколько логика совместной их работы соответствтует запланированной? Тут мы подошли к стратегии интеграционного тестирования. Для интеграционного тестирования также справедливо и целесообразно использование механизма заглушек. Данный вид тестирования подразделяется на нисходящий и восходящий. Для пояснения этих терминов давайте рассмотрим java-приложение, позволяющее бронировать билеты в кинотеатр. Рассмотрим его в разрезе уровней реализации (модулей): пользовательский интерфейс, интерфейс сервера к пользователю, интерфейс сервера к базе данных, драйвер базы данных. При нисходящем тестировании, сперва мы бы составили и "прогнали" набор тестов для пользовательского интерфейса, поставив заглушки на "нижних" входах/выходах. Заглушки бы возвращали заранее определенные ответы, детерминированность которых принималась нами как допустимое приближение функциональности, позволяющее с достаточной степенью уверенности оценить работу верхнего уровня приложения. Далее, "снизу" мы бы присоединили сервер обработки запросов, "воткнув" заглушку на уровень общения с драйвером базы данных. При восходящем тестировании мы бы проверили сперва драйвер базы данных, а затем последовательно присоединяли бы модули "сверху". Выбор между нисходящим и восходящим тестированием обуславливается не столько порядком реализации модулей (хотя влияние данного фактора также не стоит отвергать) сколько прогнозированием мест появления багов. Идея состоит в том, что более весомые ошибки необходимо локализовывать на ранних стадиях разработки.
При разработке тестового сценария для тестирования методом белого ящика, необходимо определить критерии допустимости покрытия. Делается это для того чтобы выявить степень покрытия приложения тесткейсами, а в дальнейшем сделать вывод о том, насколько качественный продукт подготовила компания на данной стадии его производства. Существует несколько видов подобных критериев, но наиболее известны и признанны три из них: покрытие команд, покрытие условий и покрытие путей. Остановимся подробнее на каждом из них:

1. Покрытие команд.
Данный критерий говорит нам о том, что необходимо разработать такой набор тесткейсов, которые затронут КАЖДЫЙ оператор в программе хотя бы один раз. Рассмотрим для примера java код простейшего класса, имеющего нетривиальную логику. В суть этой логики вникать не имеет никакого смысла. Главное — это то, что в тестируемом классе имеется набор потенциальных путей, возможных для прохождения. Рассматриваемый критерий позволяет нам выделить минимальный набор тесткейсов (пар значений для входных данных), удовлетворяющих критерию покрытия команд. Количество тесткейсов в данном случае равно одному. Эта пара значений: value_1=5, value_2=6 и соответствующий ожидаемый результат: 11.

1  public class TestClass {
2     public int testMethod(int value_1, int value_2){
3         int result=-1;
4         if (value_1==5){
5             result=0;
6         }
7         if(value_1!=value_2){
8             result=value_1+value_2;
9         }
10        return result;
11    }
12 }


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

2. Покрытие условий
Данный критерий более силён по сравнению с предыдущим. Он предполагает, что тесты отвечающие ему, проходят через каждое условие в коде хотя бы один раз. В нашем конкретном примере, тест, отвечающий критерию покрытия команд, отвечает и критерию покрытия условий, т.к. значения проверяются в обоих боках if.

3. Покрытие путей. Для того чтобы составить набор тестов, отвечающих данному критерию, полезно нарисовать блок-схему либо граф выполнения программы. После построения схемы, написанные тесты в совокупности должны провести тестируемый код по всем "стрелочкам". Относительно нашего примера таких тесткейсов будет 4. Если рассматривать их в виде "[(входное-значение-1, входное-значение-2), ожидаемый результат]: покрываемый путь", то описание тестового набора будет выглядеть следующим образом:
[(5,5),0]: 2-3-4-5-7-10
[(5,4),9]: 2-3-4-5-7-8-10
[(4,4),-1]: 2-3-4-7-10
[(4,5),9]: 2-3-4-7-8-10

Вы в праве задать вопрос: "Почему мы используем цифру 4 а не 8? Или не 11. Или не -3". Для ответа на этот вопрос в теории тестирование введено понятие классов эквивалентности. Классы эквивалентности — это классы входных данных, любой элемент из которых при успешном завершении теста на его основе, гарантирует успешность тестов и на остальных элементах из данного класса эквивалентности. В нашем конкретном примере, мы разбили все входные данные на два класса: первый состоит из одной лишь цифры 5, а второй — из всех остальных цифр. Вопрос методики разбиения на классы так же сугубо субъективен и зависит от множества факторов.
Рассмотренные подходы не предназначены для поиска ошибок, связанных с невыполнением ограничений, наложенных спецификациями или иных ограничений. Для этого следует разрабатывать индивидуальные тесты с учетом установленных нюансов. Выбор в пользу тестового набора, удовлетворяющего тому или иному критерию обуславливается многими факторами и является предметом обсуждения внутри компании. Стоит отметить, что для проверки качества тестового набора, часто, проводят т.н. мутационное тестирование. Для этого в код вносят заведомо ошибочные участки Читать далее

Тестирование программных продуктов

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

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

Усредненная структура компании, занимающейся разработкой программного обеспечения, выглядит следующим образом:
Маркетинговая служба. Занимается исследованием рынков, требований потенциальных заказчиков и расчетом соответствующих рыночных рисков. После перечисленных исследований, отдел подготавливает соответствующую документацию, в котором общими словами и требованиями, описывает продукт, требующий разработки и внедрения на рынок. Данная документация носит название MRD, т.е. Market Requirement Document
Служба документации. Занимается подготовкой документации различных видов, начиная от руководств по продукту, заканчивая конкретизацией документа MRD, называемого PRD — Product Requirement Document.
Служба разработки. Занимается непосредственно разработкой архитектуры приложения и его кода. Ядро компании и, часто, самый многочисленный отдел в ней. На основе PRD разрабатывается т.н. "дизайн-спецификация", описывающая общие принципы имплементации каждой выделенной части продукта.
Служба тестирования. Отдел, о котором пойдет речь в данной статье. Занимается проверкой корректности различных частей продукта на каждой стадии его разработки. В маленьких компаниях, численностью до 15 человек, выделять специальный отдел тестирования не имеет особого смысла, т.к. подобные команды разрабатывают малобюджетные, высокооборачиваемые продукты, и могут позволить себе быстрое тестирования средствами самих разработчиков. В случае, когда компания разрабатывает большое количество продуктов, либо продукт один, но масштабный, без отдельного департамента по тестированию не обойтись

Прежде чем вплотную подойти к особенностям профессии инженера по тестированию, необходимо ознакомиться со средой его обитания. С ключевыми терминами, с целями и задачами, а также со сложившимися стереотипами, заложниками которых, многим инженерам приходится становиться в силу начальной стадии развития данного направления в России. Основными "друзьями" специалиста в рассматриваемой области являются "баги", "тесткейсы", "бактрэкинговые системы", а также "инструменты автоматизации". Баг (Bug-жук) — ошибка, отклонение работы приложения от ожидаемого. Легенда появления этого термина говорит о том, что некие американские инженеры, разбирающиеся с поломкой электронного утсройства, обнаружили, что виной всему стал мотылек, застрявший между контактами. Дальнейшее развитие QA-индустрии согласилось с лаконичностью и информативностью термина, в наши дни прочно засевшего в сленге IT-специалистов. Чтобы как-то формализовать подход к тестированию, структурировать его, зафиксировать степень покрытия и получить базу, на которую можно ссылаться при предъявлении претензий свзанных с появлением багов, тестировщики пользуются т.н. тесткейсами. Тесткейс (Test Case — тестовый случай) представляет собой формализацию юзкейса (use case — последовательность шагов, рассматриваемая в рамках стандартного использования приложения) с целью зафиксировать отклонение или неотклонение результата от ожидаемого. Количество тесткейсов на один продукт может исчисляться сотнями и даже тысячами. Каждый такой случай покрывает определенный процент функциональности приложения, а итог в идеале должен стремиться к 100%. Для того, чтобы собрать статистику, зафиксировать ошибки и провести их от стадии открытия до стадии исправления и закрытия, инженеры по тестированию (строго говоря, не только они — данный инструмент является ядром взаимодействия между отделами) пользуются т.н. бактрекинговыми системами (Bug Tracking — отслеживание багов). Такие системы, часто представляют собой сервера с веб-интерфейсом, имеющие широчайшие возможности по структуризации контента. В общих чертах процесс использования данных систем сводится к следующей последовательности:
Инженер по тестированию, выполняя тестовые мероприятия (будь то выполнение тесткейсов, либо просто "игра" с тестируемым приложением) обнаруживает поведение, отличное от ожидаемого.
Обнаружив баг, инженер заносит информаци о нём в багтрекинговую систему. Система присваевает ему статус "New".
Далее процесc зависит от используемой системы, а так же от её настройки. Т.к. ошибка, занесенная в систему, должна переместится в чью-либо зону ответственности, необходимо определить пользователя, на которого ошибка будет переведена (assigned). Этот процесс может проходить как автоматически (в результате анализа системой входной информации об ошибке) так и вручную (при просмотре списка ожидающих багов менеджером проекта, например)
Запись об ошибке передается программисту для исправления (to be fixed). Программист принимает решение, которое может обернуться как минимум четырьмя исходами: согласиться с тем, что данное поведение приложения ошибочно и исправить его; не согласиться с тем, что это ошибка, и отправить запись обратно в отдел тестирования со статусом "Not A Bug" при этом обосновав своё решение; отправить ошибку обратно в отдел тестирования со статусом "Can Not Reproduce" при невозможности воспроизвести данный результат на своей копии приложения; отправить запрос дополнительной информации, вовлеченному пользователю (Info request).
После того, как баг приходит обратно в отдел тестирования, инженеру необходимо провести верификацию его текущего статуса. В случае исправления ошибки, тестировщику необходимо как минимум пройти описанный тесткейс и убедиться что на новой версии приложения, результат описанных действий равен ожидаемому. В случае статуса "Not A Bug" необходимо либо согласиться с этим (получив консультации заинтересованных лиц), либо не согласиться и отправить ошибку обратно разработчикам. При верификации статуса "Can Not Reproduce", необходимо убедиться, что проблема всё ещё существует, а также в том, что шаги её достижения были описаны верно.
После верификации баг отправляется менеджеру отдела тестирования в статусе "To Be Closed". Менеджер принимает решение о финальном закрытии или незакрытии данной ошибки

Описанный процесс в теории тестирования называется жизненным циклом бага. Весь жизненный цикл ошибки отражается в багтрэкинговых системах, в последствие позволяющий накопить статистику по ошибкам, провести их анализ и сделать соответствующие выводы. Стоит также отметить, что при занесении бага в систему отслеживания жизненного цикла, одним из свойств новой записи становится приоритет данного бага, который может измениться в процессе эволюционирования этой записи. Стандартно выделяют четыре приоритета: Low, Medium, High и Critical. Имея перед собой статистику по текущему проекту, можно определить критерий выпуска релиза. Обычно, обязательным критерием является отсутствие багов с приоритетами Critical и High на момент сдачи проекта. Отношение к остальным багам сугубо индивидуально для каждой компании. Такие ошибки могут исправляться как внутри текущего релиза, так и в следующих версиях продукта, если того требует рыночная ситуация.

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