с чего начинается тестирование по
Тестирование ПО с нуля: что должен знать начинающий QA
Тестирование ПО. Основные виды
Тестирование программного обеспечения может быть ручным (мануальным) и автоматизированным. По направлению тестирование делится на нагрузочное и инсталляционное. Также не забываем про тестирование безопасности и удобства пользователя.
Ручное (мануальное) — вид тестирования, который подходит самым усидчивым и внимательным. Все проверки тестировщик проводит вручную, без использования программ.
Автоматизированное тестирование проводится с использованием программных средств. Тестировщик или программист пишет специальный код для проверки ПО.
Нагрузочное ещё называют тестированием надежности. С его помощью проверяется работоспособность ПО при длительных нагрузках на систему или базу данных.
Инсталляционное тестирование проверяет правильность процессов загрузки, установки и удаления программы.
Тестирование безопасности — этот вид проверки определяет, насколько ПО защищено от любых атак, а также выясняет, находятся ли данные пользователей и системы в безопасности.
Тестирование удобства пользователя — в этом случае тестировщик становится пользователем и определяет, насколько удобно пользоваться программой.
Сам процесс тестирования может быть разным. Например, часто практикуется проверка по готовым тестам, или когда в ходе тестирования специалист пробует и пишет новые тесты. Третий вид тестирования — свободное. Тестировщики проверяют ПО, основываясь на своём опыте.
Уже зная все виды тестирования, ты можешь определить для себя, в какое направление углубляться и на что обращать внимание при обучении. Для самых внимательных тестировщиков без особого опыта подойдёт ручное тестирование. Чтобы заниматься автоматизированным тестированием, тебе нужно изучить языки программирования и разобраться в кухне разработки ИТ-продуктов. В обоих случаях, тебе пригодятся теоретические знания. Черпай их из полезных ресурсов.
Список вопросов, которые тебе зададут на собеседовании
Первым вопросом, конечно, будет: почему вы решили стать тестировщиком? Здесь нет правильного ответа, но есть некорректные. Не стоит отвечать, что это наиболее простой путь входа в ИТ. Расскажи, почему тебе интересно тестирование. Например, благодаря труду тестировщика выпускается удобный для пользователя и качественный продукт. Скажи, что тебе хочется быть частью этого процесса.
Далее HR или техспециалист захочет проверить общие знания в тестировании. Ты можешь услышать вопросы: Что такое тестирование? В чём его цель? Что такое ошибка/баг? Тебе нужно ответить что-то вроде этого: «Тестирование — это не просто поиск ошибок. Это процесс, который выявляет насколько продукт соответствует предъявленным ему требованиям. Ошибка же — это не просто причина некорректной работы программы. Это несоответствие требованиям, которые предъявлены к продукту».
И, конечно, тебя проверят на полноту теоретических знаний. Подготовь ответы на вопросы: Какие виды/типы/классы/методы тестирования вы знаете? Чем они различаются? В чём суть процесса тестирования? Из каких этапов он состоит? Какие бывают виды и цели тестовой документации? Назовите техники тест-дизайна.
Чтобы разбираться в основных аспектах теории тестирования, обратись к книгам по профессии.
Книги по тестированию, с которых ты можешь начать
«Тестирование dot com», Роман Савин
Каждому, в том числе и самому-самому начинающему. К ней можно по-разному относится за её относительно лёгкий, даже ребяческий способ изложения информации, однако же пользы в этой книге достаточно. Это must-read для начинающих тестировщиков или тех, кто хочет понять суть процесса. Книга поможет «войти» в тему, познакомит с терминологией, соотнесёт русские и английские понятия, на примерах покажет и объяснит решение разных задач. Кроме того, это одна из немногих книг, написанных на русском языке, что исключает ошибки перевода и неточности толкования. Подкупит начинающих тестировщиков и оформление. В общем, эта книга – первый шаг в сторону тестирования, без неё как без азбуки.
«Тестирование программного обеспечения. Базовый курс», Святослав Куликов
Книга подойдёт для новичков, но что-то интересное в ней для себя найдёт и опытный тестер. Издание не усложнено академической дотошностью и скучностью изложения, однако наполнено классификациями, таблицами и советами. Здесь много описаний ошибок и мифов, типичных заблуждений и терминов. Впрочем, некоторые отмечают, что какие-то части книги не то чтобы не нужны, но чрезвычайно загружены: легко забываются и не всегда легко воспринимаются даже опытными тестировщиками. Однако систематизация лишней не будет, верно?
Особое преимущество книги в том, что она распространяется в электронном варианте и постоянно дополняется свежей информацией.
В книге «Тестирование программного обеспечения» Сэма Канера, Джека Фолка, Енга Кека Нгуена от А до Я объяснены методы тестирования. Она содержит истории и опыт ИТ-компаний. Авторы дают советы новичкам и профессионалам. Учебник непрост в прочтении, но заменит тебе многие другие ресурсы.
«Lessons Learned in Software Testing» — более современная книга от тех же авторов. Она меньше наполнена теорией и подходит тем, кто любит учиться на чужих ошибках. Тут приведены реальные проблемы, пути их решения и полезные советы.
Из книги «Как тестируют в Google» Арбона Джейсона, Каролло Джеффа, Уиттакера Джеймса ты узнаешь про все процессы тестирования в крупной международной компании. Прочитаешь, через что проходят кандидаты на должность тестировщика, которые пробуют попасть в Google. Обещаем много юмора и иллюстраций!
Фундаментальная теория тестирования
В тестировании нет четких определений, как в физике, математике, которые при перефразировании становятся абсолютно неверными. Поэтому важно понимать процессы и подходы. В данной статье разберем основные определения теории тестирования.
Перейдем к основным понятиям
Тестирование программного обеспечения (Software Testing) — проверка соответствия реальных и ожидаемых результатов поведения программы, проводимая на конечном наборе тестов, выбранном определённым образом.
Цель тестирования — проверка соответствия ПО предъявляемым требованиям, обеспечение уверенности в качестве ПО, поиск очевидных ошибок в программном обеспечении, которые должны быть выявлены до того, как их обнаружат пользователи программы.
Для чего проводится тестирование ПО?
Принципы тестирования
QC (Quality Control) — Контроль качества продукта — анализ результатов тестирования и качества новых версий выпускаемого продукта.
К задачам контроля качества относятся:
К задачам обеспечения качества относятся:
Верификация и валидация — два понятия тесно связаны с процессами тестирования и обеспечения качества. К сожалению, их часто путают, хотя отличия между ними достаточно существенны.
Верификация (verification) — это процесс оценки системы, чтобы понять, удовлетворяют ли результаты текущего этапа разработки условиям, которые были сформулированы в его начале.
Валидация (validation) — это определение соответствия разрабатываемого ПО ожиданиям и потребностям пользователя, его требованиям к системе.
Пример: когда разрабатывали аэробус А310, то надо было сделать так, чтобы закрылки вставали в положение «торможение», когда шасси коснулись земли. Запрограммировали так, что когда шасси начинают крутиться, то закрылки ставим в положение «торможение». Но вот во время испытаний в Варшаве самолет выкатился за пределы полосы, так как была мокрая поверхность. Он проскользил, только потом был крутящий момент и они, закрылки, открылись. С точки зрения «верификации» — программа сработала, с точки зрения «валидации» — нет. Поэтому код изменили так, чтобы в момент изменения давления в шинах открывались закрылки.
Документацию, которая используется на проектах по разработке ПО, можно условно разделить на две группы:
Этапы тестирования:
Программный продукт проходит следующие стадии:
Требования
Требования — это спецификация (описание) того, что должно быть реализовано.
Требования описывают то, что необходимо реализовать, без детализации технической стороны решения.
Отчёт о дефекте (bug report) — документ, который содержит отчет о любом недостатке в компоненте или системе, который потенциально может привести компонент или систему к невозможности выполнить требуемую функцию.
Атрибуты отчета о дефекте:
Жизненный цикл бага
Severity vs Priority
Серьёзность (severity) показывает степень ущерба, который наносится проекту существованием дефекта. Severity выставляется тестировщиком.
Градация Серьезности дефекта (Severity):
Градация Приоритета дефекта (Priority):
Тестовые среды
Основные фазы тестирования
Основные виды тестирования ПО
Вид тестирования — это совокупность активностей, направленных на тестирование заданных характеристик системы или её части, основанная на конкретных целях.
Автор книги «A Practitioner’s Guide to Software Test Design», Lee Copeland, выделяет следующие техники тест-дизайна:
Методы тестирования
Тестирование белого ящика — метод тестирования ПО, который предполагает, что внутренняя структура/устройство/реализация системы известны тестировщику.
Согласно ISTQB, тестирование белого ящика — это:
Тестирование чёрного ящика — также известное как тестирование, основанное на спецификации или тестирование поведения — техника тестирования, основанная на работе исключительно с внешними интерфейсами тестируемой системы.
Согласно ISTQB, тестирование черного ящика — это:
Тестовая документация
Тест план (Test Plan) — это документ, который описывает весь объем работ по тестированию, начиная с описания объекта, стратегии, расписания, критериев начала и окончания тестирования, до необходимого в процессе работы оборудования, специальных знаний, а также оценки рисков.
Тест план должен отвечать на следующие вопросы:
Чаще всего чек-лист содержит только действия, без ожидаемого результата. Чек-лист менее формализован.
Тестовый сценарий (test case) — это артефакт, описывающий совокупность шагов, конкретных условий и параметров, необходимых для проверки реализации тестируемой функции или её части.
Атрибуты тест кейса:
С чего начинаются тесты
Тестов много не бывает. И речь идёт не только о наращивании их количества (что само по себе, конечно, тоже хорошо) — речь идёт о разнообразии самих видов тестов. Даже не напрягая воображение можно вспомнить несколько способов протестировать ваше приложение: Unit-тесты, интеграционные тесты, API-тесты, системные тесты… и это не вспоминая о том, что тесты ещё бывают функциональными, нагрузочными, направленными на отказоустойчивость.
Но с чего же начинать писать тесты для новых проектов? Лично для меня, как для программиста, самый интуитивный ответ — это Unit-тесты. Однако опрометчиво накидываться на сочинение Unit-тестов может не только оказаться бесполезым занятием, но даже нанести вред в будущей разработке проекта.
Поэтому в этой статье я хочу предложить вам альтернативу и расскажу о том, почему лучше всего в самую первую очередь писать самые сложные тесты (системные), а затем уже — все остальные.
А можно всех посмотреть?
Я думаю, многие из вас видели ту или иную версию вот этой картинки:
Существуют различные вариации этой картинки — может меняться количество слоёв, их название, состав, но суть остаётся неизменной: тестирование программ можно разбить на несколько уровней, и при этом чем выше мы поднимаемся по этим уровням — тем дороже и сложнее становится разработка и проведение тестов — и, соответственно, количество тестов на уровне N+1 будет неизменно меньше, чем на уровне N.
Я хочу вкратце пробежаться по этой пирамиде, обрисовав пару мыслей по каждому виду тестов. Если вы и так отлично в этом разбираетесь, то можете сразу пролистать сюда
Unit-тесты
В основе пирамиды лежат Unit-тесты (или, в русском варианте, модульные тесты). Unit-тесты направлены на тестирование небольших модулей программы. Зачастую под модулем понимается отдельный класс или даже функция.
Несколько особенностей Unit-тестов:
Интеграционные тесты
На следующем уровне пирамиды обычно указываются интеграционные тесты. Интеграционные тесты направлены на тестирование больших обособленных блоков программы и их взаимодействие между собой (опционально). Под блоком может пониматься отдельная библиотека с частью функционала программы, или же просто большой обособленный участок кода, который слишком велик для покрытия обычными Unit-тестами. Если же программа не бьётся на обособленные блоки и имеет монолитную архитектуру, то интеграционные тесты могут прогоняться для всей программы целиком, но при этом программа помещается в «вакуум» — никак не общается и не взаимодействует с «внешним миром».
Несколько особенностей интеграционных тестов:
API-тесты
Также в пирамиде иногда выделяют API-тесты. Иногда их относят к интеграционным, иногда — как отдельный уровень, но сути это не меняет. Если какая-то часть программы имеет чётко выраженный и оформленный API, то можно выстроить тесты, «дергая» этот API и сверяя фактический результат с ожидаемым. Часто такое можно встретить в распределённых приложениях.
Сейчас такой вид тестов получил просто огромное распространение за счёт очень большой популярности REST API. Это очень удобный способ связывать клиент-серверные приложения между собой, и поэтому, конечно, создаётся очень заманчивое желание абстрагироваться от клиента и протестировать только серверную составляющую, дергая за «ниточки» API.
Несколько свойств этого вида тестирования:
Тем не менее, нужно заметить, что этот вид тестирования возможен только при наличии у программы (или у её компонентов) чётко сформированного API. Что бывает далеко не всегда (например, по соображениям безопасности, или просто наличие API не предусмотрено архитектурой приложения).
Системные тесты
На вершине пирамиды располагаются системные (или, как их иногда называют, end-to-end) тесты. Иногда на вершине пирамиды указывают UI-тесты, но лично я бы не стал выделять этот вид тестов в отдельный уровень. Впрочем, это лишь дело вкуса, потому что UI-тесты можно считать подмножеством системных тестов.
Системные тесты направлены на тестирование всей программы в целом, с учётом окружения, в которой программе предстоит работать. Это уточнение очень важное, ведь программа редко когда может работать «сама по себе». Программа работает на одном или нескольких (в случае распределенных приложений) конкретных компьютерах. И на разных компьютерах (в разных условиях) тестируемая программа может повести себя по-разному. Например, клиент-серверное приложение может работать замечательно в обычной сети, но при этом может оказаться неработоспособным при наличии между клиентом и сервером маршрутизатора с настроенным NAT.
Такой вид тестов является самым дорогим, самым сложным и самым трудноавтоматизируемым видом тестов. Зачастую системные тесты настолько сложно автоматизировать, что их и вовсе прогоняют вручную, что ещё больше увеличивает их стоимость. При этом этот вид тестов обладает одним неоспоримым и важнейшим преимуществом: это тестирование программы в том виде, в котором её увидит пользователь. Больше того, системные тесты позволяют даже воспроизвести условия различных пользователей, чтобы убедиться, что у всех пользователей всё работает хорошо.
Несколько заметок о системных тестах:
Отдельно хочется рассказать про автоматизацию. Системные тесты чрезвычайно тяжело автоматизируются. Самостоятельно автоматизировать такие тесты практически не представляется возможным, но при использовании готовых инструментов автоматизации ситуация немного упрощается. На рынке существует довольно много коммерческих решений по автоматизации системных тестов, но с бесплатными решениями ситуация гораздо хуже.
Что ж, ликбез в теорию я заканчиваю, и перехожу к самой интересной части — какой вид тестов лучше писать в первую очередь?
Не спешите с Unit-тестами
Я думаю, что рисунок с пирамидой тестов создаёт обманчивое впечатление. Этот рисунок призван лишь продемонстрировать распределение количества тестов по разным уровням в зависимости от их стоимости. Но вместо этого он создаёт ощущение, что тесты более высокого уровня как бы «базируются» на тестах более низкого уровня. И, соответственно, может показаться, что «пока не разберусь с Unit-тестами, об интеграционных и говорить нечего. Ну а до системных хорошо если вообще доберёмся». И я считаю, что это в корне неверная позиция.
Представим ситуацию, что вы разрабатываете совершенно новое приложение. Неважно, как именно вы его разрабатываете — на основе четко сформированных требований или же «по наитию». В какой-то момент времени вам (надеюсь) захочется написать тесты. Это может случиться как только у вас получится что-то работающее, или же тесты окажутся вообще вашим самым первым шагом — если вы придерживаетесь концепции TDD (Test Driven Development). Неважно когда, но этот момент настанет. И о каких же тестах вы подумаете в первую очередь?
Лично я, как разработчик, всегда думаю в первую очередь о Unit-тестах! А почему бы и нет? Ведь для меня программа — это, в первую очередь, исходный код. Если я сам пишу код и знаю, как он работает/должен работать, то для меня самый логичный первый шаг — покрыть его тестами. Больше того, я уже знаю, как это делается, я делал это тысячу раз, это зона моего комфорта. Поэтому я с чувством выполнения великой миссии (тесты это же хорошо!) начинаю стандартную возню с Unit-тестами: скачиваю свой любимый фреймворк, продумываю абстрактные классы вместе с интерфейсами, занимаюсь mock-ированием объектов… И радуюсь, какой я молодец.
И тут я загоняю себя в две потенциально-опасные ситуации. Посмотрим на первую проблему.
Кто может быть первым кандидатом на Unit-тесты? Лично я бы начал с обособленных участков кода и классов, которые выглядят вполне самостоятельными. Например, я решил, что для моего проекта мне понадобится самописная хеш-таблица. Это же отличный кандидат на покрытие Unit-тестами! Интерфейс понятен и меняться не будет, так что написать тесты — сам бог велел. И вот я воодушевлённо трачу своё рабочее время, накидывая десятки тестов. Может быть, я даже выловлю несколько багов в своём коде (боже, как я хорош, как мощны мои тесты) и… и спустя два месяца я вдруг понимаю, что хеш-таблица мне вовсе не нужна, лучше бы её заменить базой данных. И все мои рабочие часы на Unit-тесты (и выловленные баги) летят в помойку.
Обидно? Ну что ж, с кем не бывает, ничего страшного. Это ведь не повод отказываться от Unit-тестов, верно? Сделаем заметку и рассмотрим вторую опасную ситуацию.
Отловив все очевидные участки кода, которые можно покрыть Unit-тестами, вы вдруг понимаете, что вы покрыли всего 10% кода (ну нет у вас сейчас четких обособленных модулей с внятными интерфейсами на такой стадии проекта). Тогда вы начинаете беспощадно рефакторить свой код — выделяете абстрактные классы, выстраиваете зону ответственности между модулями, инкапсулируете, инкапсулируете, инкапсулируете… занимаетесь, в общем-то, полезными делами, честно говоря. Ну и каждый свой успех отмечаете очередной порцией Unit-тестов, ведь ради них, родимых, всё и затевается!
Спустя пару недель работы вы получаете 60% покрытого тестами кода. У вас появилась сложная иерархия классов, mock-объекты, а общее количество Unit-тестов перевалило за 100500. Всё хорошо, так ведь?
Всё хорошо ровно до тех пор, пока вы не увидите, что вашу архитектуру можно было бы улучшить (а с развитием проектов, особенно новых, такие наблюдения случаются регулярно). И вместо того, чтобы смело ринуться в дебри рефакторинга, вы начинаете грустно думать о 100500 Unit-тестах и о том, как теперь вам придётся их переделывать. Вы становитесь заложником своих собственных Unit-тестов, которые начинают сковывать вашу гибкость в принятии архитектурных решений. И выбор у вас получается… так себе. Либо решиться на рефакторинг и спустить в унитаз всё время, потраченное на Unit-тесты, либо (ещё хуже) — оставить всё как есть, и затем бороться с не самой удачной (как вы теперь понимаете) архитектурой.
Звучит так, как будто я просто персонально терпеть не могу Unit-тесты и пытаюсь отговорить вас от их использования, так?
Вовсе нет. Просто для любого нового проекта это абсолютно нормальная ситуация — в какой-то момент понять, что изначальная архитектура или затея вышла не слишком удачной — и что нужно всё (или практически всё) переделывать. Вам всё равно с высокой долей вероятности придётся через это пройти. И наличие Unit-тестов вас не только не спасёт — оно даже сыграет с вами злую шутку: вместо того, чтобы взвешенно и объективно принять решение о реструктуризации кода, вы будете только грустно вспоминать о потраченных часах и даже днях на составление сотен, тысяч юнит-тестов. Мне было бы жалко времени, потраченного на Unit-тесты, которые теперь надо выкинуть в помойку и начинать писать заново.
Лучше спешите с системными тестами!
Так что же я предлагаю? А предлагаю я взглянуть на старый рисунок по-новому:
Почему бы не начинать тестирование программы с разработки системных тестов? Это может прозвучать немного странно, неинтуитивно, но если немного задуматься — это не такой уж и плохой план. Судите сами.
Звучит неплохо, не правда ли? Причём, системные тесты обладают ещё рядом очень приятных бонусов:
Остаётся только одна проблема: системные тесты с трудом поддаются автоматизации. Возможно, это одна из причин, почему сейчас системные автотесты или оставляют «на потом», или вообще ограничиваются ручным тестированием.
Впрочем, сейчас на этом фронте не всё так уж и плохо — существует очень много коммерческих решений, которые позволяют в том или ином виде решить эту проблему: Testcomplete, Squish, Ranorex, Eggplant — это лишь самые известные примеры таких систем. У всех у них есть свои достоинства и недостатки, но в целом со своей задачей по автоматизации системных тестов они справляются (хоть и стоят очень немалых денег).
А вот среди бесплатных решений выбора особо нет. По крайней мере не было.
Совсем недавно я выпустил инструмент, который должен немного исправить вселенскую несправедливость и дать людям возможность бесплатно автоматизировать системные тесты. Этот инструмент называется платформой Testo — и поподробнее про него можно почитать тут.
А что же другие тесты?
Заметьте, что я сосредоточился на том, что стоит начинать с системных тестов, потому что это даёт определенные неплохие бонусы. Но это отнюдь не означает, что стоит пренебрегать другими видами тестов.
В самом деле, системные тесты дают неплохое представление о том, что программа в целом работает, но при этом они не ограничивают вашу свободу при работе скальпелем в вашем проекте. Но это не отменяет того факта, что системные тесты всё равно остаются довольно тяжеловесными (даже с учётом автоматизации) и их действительно невозможно клепать с той же легкостью и скоростью, как API-тесты или, тем более, Unit-тесты.
В развитием проекта вы обнаружите, что вас уже не устраивает только проверка «в целом всё работает». Со временем архитектура вашего нового приложения неизбежно «устаканится», крупных изменений будет всё меньше и меньше. В какой-то момент вы поймёте, что вы хотите навесить побольше проверок на какой-нибудь компонент (потому что он уже точно никуда из проекта не денется, и его интерфейс точно проработан), или даже на конкретный класс… А для особо важных участков кода и вовсе желательно проработать все возможные ветвления. Или же вам очень интересно, как поведёт себя программа при непосредственном обращении к API. Чувствуете, да? Вот и другие тесты снова в деле!
На основе всего вышеизложенного, я бы хотел предложить следующий вариант развития тестов в проекте:
Причём, самое интересное, что за счёт большей легкости составления интеграционных и Unit-тестов их со временем станет гораздо больше, чем сложных системных тестов. Вот мы и получаем в итоге свою пирамиду тестов, только построили мы её сверху вниз.
Итоги
Вроде бы про разработку «от общего к частному» уже давным давно всё известно вдоль и поперёк, но при этом тесты всё равно упорно составляются «от частного к общему». Возможно, это дело привычки, а возможно — в том, что так просто удобнее — ведь написать двадцать Unit-тестов всегда проще, чем пару системных тестов.
Но по мере развития инструментов для автоматизации системных тестов перспектива сходу автоматизировать end-to-end тесты уже не кажется такой уж пугающей. Возможно, вам понравится разрабатывать тесты «сверху вниз» — ведь так их можно разрабатывать ровно по мере их надобности.