18 июня 2012 г.

Тестирование: Ручное или Автоматизированное?

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

Я думаю стоит сразу упомянуть, что на всех этапах мы использовали:

  • Модульные тесты с покрытием около 50%
  • Continuous Integration с запуском модульных тестов (в последствии и интеграционных), автоматической сборкой и выпуском релиза
  • Пересечение из гибких методологий под общим названием ScrumbanXP

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

Шаг 1. Тестировщиков нет

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

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

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

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

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

Шаг 2. Начало автоматизации тестирования

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

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

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

Для записи тестов попробовали разные варианты, остановились на Selenium. Сначала тесты писали на API самого Selenium. Со временем начала создаваться обертка над низкоуровневым API и эта обертка превращалась в некий DSL для тестирования.

Пока тестировщик разбирался с продуктами для тестирования и налаживал процесс автоматизации тестов разработка не останавливалась. Мы должны были выпускать новые версии после каждой 1-2 итераций. Тестировщик постоянно находился в стадии погони за программистами. Его цель была 100% покрытием сценариев, чтобы мы могли спокойно выпускать новые версии не боясь багов.

Шаг 3. Борьба за зеленые тесты

Проблемы с автоматизацией тестирования оказались для нас неожиданными. Фактически мы не были к ним готовы.

Долгая обратная связь

Чем больше была система, тем больше мы писали тестов. Тесты начали работать реально медленно. Если они проходили за 14 часов - это была невероятная удача. Со временем тесты перестали укладываться в промежуток между 18.00 прошлого дня и 9.00 текущего дня. Мы не получали от тестов обратную связь, возникали простои в работе. Бывало еще, что свет выключат или сервер перезагрузится, тогда потери времени были слишком большие.

Зеленые тесты? Нет, не видел

Зелеными тесты не были никогда. Правда один раз были, 30 декабря они запустились и выдали результат как 100% зеленые. Наверное это был их подарок нам на Новый год. Больше такого за всё время не было.

Почему они не были зелеными? Для этого было несколько причин:

  • Хрупкие тесты - интерфейс постоянно менялся и тесты не успевали за этими изменениями.
  • Негибкие тесты - архитектура системы постоянно совершенствуется, находятся обобщающие решения для гибкости кода. Код тестов (описание) тоже надо рефакторить и обобщать, чтобы их было легче поддерживать. Например, у нас должно появиться много типовых workflow с незначительными изменениями. Разработчики придумывают архитектуру, которая будет достаточно гибкой, чтобы позволять быстро реализовывать эти workflow. Соответственно, архитектура тестов должна совершенствоваться аналогично и «успевать» за совершенствованием архитектуры кода, чего сделано не было из-за недостаточной квалификации тестировщика. Из- за того, что архитектура тестов «не успевает» за архитектурой кода, программисты реализуют фичи всё быстрее и отставание тестировщика накапливается
  • Минорные баги - тесты не всегда находили критические баги, иногда они падали из-за незначительных багов-недочетов, о которых мы знали, но исправлять их было не приоритетно. Для этого даже специально сделали плагин для TeamCity и можно было смотреть должен тест упасть или нет. Набор падающих тестов с минорными багами не давал тестам быть зелеными.
  • Нечитаемые тесты – например, у нас есть сложный сценарий с большим количеством действий, результат которого нужно протестировать. Соответственно, тест нельзя разбить на несколько мелких (проверяется не промежуточный результат, а конечный, который достигается в результате нескольких действий). Код такого теста нужно оптимизировать так, чтобы он оставался понятным и читаемым, чего также не удалось добиться.
  • Длинные сценарии - чтобы реализовать длинные сценарии нам надо сделать, например, 10-20 шагов. Промежуточный результат не важен, важен только конечный. С длинными сценариями возникает ряд проблем:
    • Если на 2-м шаге произошла ошибка, то ошибочным считается весь сценарий. В этом случае красный тест говорит не об ошибке в том, что он тестировал, а в ошибке шага, который был где-то в начале (могли поменять интерфейс Входа в систему).
    • В длинных сценариях шаги часто повторяются, возникает дублирование.
    • Длинный сценарий нельзя начать с середины, потому что для этого придется готовить специальное состояние системы, в котором она должна быть к N-му шагу. Это вносит дополнительную хрупкость в структуру тестов.

Из-за нестабильности тестов и того, что мы не успевали актуализировать их, нам пришлось:

  • Переключить разработчика, чтобы он помог тестировщикам перейти на SpecFlow, иначе тестировщики не удерживали объем тестов на C# коде. Руководитель отдела тестирования на тот момент делала доклад на тему Приемочные тесты на огурце
  • 70% времени тестировщики переписывали автоматические тесты, чтобы они соответствовали текущему набору функций системы. Т.е. это была работа ради самих тестов.
  • Как следствие из вышесказанного - мы наняли еще тестировщиков.

Достигнута ли цель?

У нас была цель - увидеть зеленые интеграционные тесты и, не боясь багов, залить на боевой сервер. Фактически мы этой цели так и не достигли.

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

Я волевым решение отменил работу по всем интеграционным тестам и ввел ручное тестирование с написание тестовых сценариев в Google Docs. После этого мы добили основные баги и тестирование отлично встроилось в Kanban поток.

Текущее состояние

В данный момент в моей компании мы с командой тестировщиков придерживаемся подхода: ручное тестирование + написание тестовых сценариев в Google Docs. Тестировщики вручную протыкивают все сценарии перед заливкой.

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

По факту это дает отличные результаты. В релизах у нас только минорные баги, либо баги, которые на самом деле фичи.

Против автоматизации тестирования?

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

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

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

Буду рад услышать, как развивалось тестирование в вашей компании.

Оригинал статьи на Хабре


Ссылки

Top Five (Wrong) Reasons You Don't Have Testers, Joel Spolsky

The Joel Test: 12 Steps to Better Code, Joel Spolsky

Обезьянки против роботов. Часть I (TestLabs09), Максим Дорофеев

Обезьянки против роботов. Часть II (TestLabs09), Максим Дорофеев

Обезьянки против роботов. Часть III (TestLabs09), Максим Дорофеев

Организация работы команды в Agile: разработка + тестирование

9 комментариев:

  1. У нас тестирование начиналось именно с ручного.Был нанят довольно хороший тестер – из бригады самих пользователей. Причем работал он совместителем и мог посвящать тестированию только вечера и то раз в два дня.Оговорюсь, что у нас было не веб-приложение, и клиентам мы поставляли помимо программ еще и скрипты изменения БД.Тестирование проводилось на виртуалках, на которых было установлено все, что необходимо для работы системы (СУБД, дрова и пр.), но, тем не менее, она была максимально приближена к условиям реального использования. Также важно, что у виртуалки была возможность делать снэпшоты и быстро (1-2мин.) откатываться к ним.Итак, раз в два дня наш тестер:1. Делал откат виртуалки к снэпшоту предыдущего релиза.2. Проливал SQL-скрипты новой версии (на этом этапе отлавливались баги в скриптах).3. Затем смотрел на доску задач и начинал «протыкивание» всех готовых на тот момент фич (у каждой фичи обязательно был прописан Acceptance Test).4. На каждый баг делался Reject фичи на доске с описанием проблемы.5. Поскольку готовых фич за два дня обычно не так много, оставшуюся часть времени тестер посвящал Exploratory Testing.6. Если обнаруживались баги, не относящиеся к фичам спринта, оформлялся отдельный Bug Report (пошаговый, конечно).7. Одним из плюсов такого подхода являлось еще и то, что тестировался еще и деплоймент, как он будет проходить у клиентов.Перед выпуском версии прогонялась небольшая регрессионка, где ловились прочие просочившиеся жуки. Надо сказать, на регрессионном тестировании багов вылезало немного и были они, в основном, некритичные. Причина как раз в регулярном тестировании в течение спринта. После выпуска релиза тестер делал очередной снэпшот (вообще, он делал и промежуточные, но снэпшот релиза он делал обязательно).Конечно, добрую часть этих шагов можно автоматизировать, но важно как раз то, что начало было положено вручную и мы довольно быстро почувствовали положительные результаты. Да и запустилась такая схема «с полпинка».

    ОтветитьУдалить
  2. Спасибо за развернутый комментарий.

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

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

    И второй вопрос в продолжение первого.
    Использование IoC при модульном тестировании - насколько это необходимо,
    обязательно, упрощает тестирование или можно безболезненно обойтись и без IoC?

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

    ОтветитьУдалить
  6. Непонятно. почему автоматические тесты не успевали за ночь, а ручное тестирование успевали сделать за рабочий день?
    Может проблема, в том что автоматическими тестами пытались выполнить слишком много однотипных сценариев.
    Мы используем ручное тестирование, с записыванием сценариев, и переводим потихоньку ручные в автоматические. 

    ОтветитьУдалить
  7. Роман, я не говорил, что тестировщики успевали за день. Тестирование всегда отставало от разработки, как минимум на 3 дня.

    ОтветитьУдалить