Классификация видов автоматизированного функционального тестирования

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

На мой скромный взгляд (IMHO), безоглядное, чуть ли не повальное увлечение автоматизированным тестированием через GUI не слишком оправдано. Хотя сама по себе автоматизацию вполне имеет право на существование. “Потому что функциональное автоматизированное тестирования бывает разное” (с) Капитан Очевидность. “И в зависимости от ситуации оправдано применение того или иного” и снова спасибо Кэпу.

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

  • “кто пишет.[программист | тестировщик]”;
  • “когда.[до кода(test first) | плюс-минус пара минут от кода (TDD) | после кода (регрессионное тестирование)]”;
  • “кто выполняет.[ программист |  тестировщик ]”;
  • “интерфейс[ GUI | API ]”.

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

Так вот, IMHO, комбинация {пишет.тестировщик; когда.после кода; выполняет.тестировщик; интерфейс.GUI} самая бестолковая и одновременно безумно популярная.

Лирическое отступление. Почему эти тесты и наиболее бестолковые и наиболее популярные одновременно? Как один из вариантов объяснения: “Это позволяет тестлиду раздуть команду”. Действительно, пусть для того, чтобы продукт “N” стал хорошим, в нем нужно найти и исправить 2000 дефектов. И сделать это надо в течение года. При мануальном тестировании нормальная “цена” нахождения 1000 дефектов - это один человекогод. Значит нужно двое тестировщиков. С учетом неравномерности загрузки трое-четверо. А вот если ввести 100% автоматизацию посредством тесткомплита или там селениума, то понадобится уже 10-20 человек. Если же тестлид по настоящему талантлив, то при поиске следующей работы в его резюме будет красоваться гордая надпись: “Руководил отделом автоматизации тестирования в 50 человек”. Ну, понятно продавать себя надо уметь. Этому сейчас даже учат. Оно конечно можно налететь на грамотного рекрутера, который воскликнет: “Восхитительно! А позвольте полюбопытствовать, сколько дефектов за год нашли эти замечательно бравые полсотни человек?”

Но не будем искать злой умысел там, где достаточно простых объяснений. Причины могут быть и другие. Ведь на первый взгляд все выглядит просто замечательно. Мы покроем тестами всю функциональность и при выпуске новой версии эти тесты будут быстро находить дефекты. Прямо таки идиллия. А теперь откинемся на диван и немного подумаем. Думать тоже иногда надо. Говорят это помогает. С чего бы тесты будут находить ошибки? Наверное, потому, что изменилась функциональность (спасибо Кэпу). Но если изменилась функциональность, то наверное нужно на конкретно эту функциональность поменять тесты? Логично. Смотрите, что получается:

  1. Софт ушел на тестирование, а тестировщики вместо того, чтобы предоставить информацию о дефектах начинают лихорадочно править тесты. Учитывая, что написание кода тестов сравнимо с написанием собственно кода, софт проведет в очереди довольно много времени. Это потери. Это ухудшение потока.
  2. Когда ошибки таки будут найдены программист будет полностью вне контекста и потратит прилично времени на переключение.

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

Т.е. перед тем как внедрять  {пишет.тестировщик; когда.после кода; выполняет.тестировщик; интерфейс.GUI} внедрите {пишет.тестировщик; когда.до кода; выполняет.программист; интерфейс.GUI}. Такой подход действительно по настоящему эффективен. Из третьих рук я слышал, что по настоящему эффективная фирма (годовой проход в расчете на сотрудника порядка $1 000 000) придерживается именно этого подхода. Конечно, чтобы перейти к такому методу нужно серьезно поднять культуру разработки, что уже само по себе сильно помогает (спасибо Кэп). Придется внедрить стандарт именования локаторов, что дополнительно сделает тесты нехрупкими (Кэп?! но как вы догадались?!). Придется ввести процедуру проектирования пользовательского интерфейса, что дополнительно сильно улучшит качество ПО. Вообще такой подход прямо таки вынуждает “мыть руки перед кодированием”. Если начать с него, то потом можно и о регрессионном тестировании подумать. База тестов-то в любом случае останется.

Прочие варианты с GUI в качестве интерфейса не слишком интересны. Наверное, можно представить себе “полуторное” программирование, при котором два программиста за одним ПК пишут интерфейс пользователя, а потом один идет писать реализацию, а другой тесты, но как то в это верится с трудом.
Комбинация {пишет.программист; когда.плюс-минус пара минут от кода; выполняет.программист; интерфейс.API} популярна, скорее, в коллективах кросфункциональщиков, где нет выделенной роли тестировщиков. Там, же где роль тестировщиков выделена, программисты пытаются от написания автоматизированных тестов уйти. Впрочем, и там где тестировщиков нет, там тоже часто эта практика часто умирает. Я полагаю, что это связано с одной из форм прокрастинации:

Посылка 1. Кодер лучше умеет писать код, нежели проектировать тестовые наборы.

Посылка 2. Человек склонен откладывать “на потом” (на практике “навсегда”) то, что он умеет не слишком хорошо.

Вывод. Кодеры будут стараться отказаться от практики юнит тестирования.

А уж причин для отказа можно придумать массу. Пойдет и такая: “написание кода тестов занимает примерно столько же времени, сколько и написание кода”. Люди умеющие логически мыслить легко отклоняют эту причину. Ведь то что, написание юнит тестов заняло 100 часов и написание кода заняло 100 часов вовсе не означает, что стало 200 вместо 100. А вот то, что стало 200 часов вместо первоначальных 300 без юнит тестов - это вполне вероятно.

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

Прежде чем двинуться дальше стоит сказать вот о чем. Капитан О: “API оно разное бывает”. Под юнит тестированием часто подразумевают тестирование отдельных классов и функций. Но гораздо интереснее, когда речь идет об интерфейсе предоставляемым сервисом и/или компонентом. Будет это SOAP, или обмен по ftp, или еще что-то не слишком важно. Чем большим оказывается число компонент и/или сервисов использующих один и тот же интерфейс, тем выгоднее становятся тесты {пишет.???; когда.до кода; выполняет.не важно; интерфейс.API}. Сначала спроектировать и описать протокол, потом тесты и только потом код. Так делать выгодно. Более того иногда это чуть ли не единственный способ сдать проект. Но об этом явно в другой статье.

PS. Я рассмотрел только интересные с моей точки зрения виды тестов. Классификацию можно расширить и рассмотреть еще какие-то виды. Но потом.

PSS. Я убежден, что найдется множество людей, которые выступят в защиту тестов вида: “{пишет.тестировщик; когда.после кода; выполняет.тестировщик; интерфейс.GUI}”. Вероятно они будут приводить казуистические доводы типа: “Эти тесты не для того, чтобы находить ошибки, а для того чтобы предотвратить их попадание в продакшен”. Мой ответ: “сами поняли чего сказали? Не поняли, так идите перечитайте.” И встречный ответ. Производительность таких автотестов считается очень простым способом - это число дефектов найденных при прогоне этих тестов деленное на число человеколет вложенных в разработку и поддержку этих тестов. Какая у вас производительность? 20 дефектов на выброшенный год? Свободны. Это смешно.

Комментариев: 3

  1. Sergey Vysotsky написал:

    > А позвольте полюбопытствовать, сколько дефектов за год нашли эти замечательно бравые полсотни человек?

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

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

    Ну и unit тесты никогда не заменяли и не заменят GUI тесты. TDD, опять же, к тестированию практически не имеет отношения - это практика поддержания чистоты кода. Чистый код тестировать быстрее и проще, да. Но TDD, повторяю, это не тестирование.

    Тестирование API не обязательно сводить к стандартизации API. Это, опять же, влечет серьезные архитектурные проблемы, а написать на практически любое API обвязку сравнительно легко, тем более что ее можно просто выдернуть из рабочего кода. Ну и обеспечение достаточного testability сильно облегчит жизнь не только тестировщикам. Жаль только, что понимание testability у людей сильно отличается от, например, вот такого: http://adam.goucher.ca/?p=141 Атрибут качества, но у многих в проектах нельзя увидеть и половины тех вещей, что описаны в статье пятилетней давности

    ЗЫ: Как в эру CI можно говорить о вещах типа выполняет.Х? Выполняет робот.

  2. SALar написал:

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

    > Проблема же поддержки большого набора GUI тестов решается дизайном самих тестов.
    Какое отношение это имеет к статье? Не надо рассказывать как работать с одним видом тестирования в отрыве от других. Давайте сравнивать относительную эффективность. Не нравится моя метрика - придумайте свою. Опишите. Будем смотреть.

    > TDD, опять же, к тестированию практически не имеет отношения - это практика поддержания чистоты кода
    Но это же не мешает этому методу улучшать продукт? Правда?

    > а написать на практически любое API обвязку сравнительно легко, тем более что ее можно просто выдернуть из рабочего кода.
    Для маленьких, простых проектов. А вот когда продукт - это совокупность полусотни (или пара тысяч - тоже бывает) подсистем, общающихся через API и некоторые API реализуют десяток тысяч методов, то смена API это такая штука, которая требует существенно времени на переписывание тестов.

    > Как в эру CI можно говорить о вещах типа выполняет.Х? Выполняет робот.
    можно роботом по крону. можно по команде. Да, скорее тут нужно вести речь о том успел программист переключить контекст или не успел. А уж что вызвало переключение - не важно. Это в статью надо бы добавить.

  3. Sergey Vysotsky написал:

    > Сотрудника нельзя. Процесс можно.
    Как минимум недосаточно. Как максимум опасно. Причины примерно те же по которым нельзя мерить находимые баги по модели Вейбулла. См. Dr. Cem Kaner “Software Testing as a Social Science”

    > Давайте сравнивать относительную эффективность.
    Относительно чего? Автоматизация это вспомогательный инструмент тестирования, состав которого сильно зависит и от процесса и от продукта над которым идет работа. Попытка смешать разные инструменты (а разные виды автоматического тестирования это и есть разные инструменты) в одну кучу, а потом их классифицировать это примерно как сравнение C++ и PHP - это разные вещи и они нужны для решения разных инженерных задач. Подводить их под один baseline как минимум странно.
    Очевидно что избыточная автоматизация через GUI это бессмысленная активность, т.к.:
    1. Тестирование сложных приложений только через GUI это слишком смелое решение
    2. Как правило избыточные GUI тесты можно заменить работой на более низких уровнях абстракции
    3. Тесты на более низких уровнях абстракции более эффективны по ряду причин (проще поддерживать, проще писать, проще работать с результатами и т.д.)
    Точно так же очевидно что полностью избежать GUI не удастся.
    Кто пишет - вопрос культуры разработки. Западные коллеги последнее время утверждают, что разработчик должен примерно 50% своего времени тратить на написание тестов, а иначе это фикция, а не разработка. Отечественных коллег согласных на это крайне мало. Менеджеров тоже. В итоге мы видим процессные решения этой проблемы напрямую противоречащие модели швейцарского сыра и просто способствующие накоплению технического долга.
    Когда выполнять? Очевидно как можно раньше. Остальное - процессные компромиссы

    > Но это же не мешает этому методу улучшать продукт? Правда?
    Делать более безопасным и предсказуемым - да. Улучшать - не обязательно. Это отличный способ избавления от мелких дыр на одном из уровней безопасности, согласно той же модели швейцарского сыра. Проблему крупных дыр он не решает - они как правило более фундаментальные. Например архитектурные

    > Для маленьких, простых проектов. А вот когда продукт - это совокупность полусотни (или пара тысяч - тоже бывает) подсистем, общающихся через API и некоторые API реализуют десяток тысяч методов, то смена API это такая штука, которая требует существенно времени на переписывание тестов.
    Тоже не согласен. Если у нас DSL поверх API, то все что нам нужно - сменить нижнюю прослойку. Если смена API не требует переписывания продукта, то клиент выдирается из рабочего кода, а для методов пишутся биндинги. Тесты переписывать не потребуется. Если же переписывание продукта требуется, то риски и трудозатраты для тестов будут несравнимо меньше чем для самого продукта.
    Архитектура и инфраструктура автоматических тестов это очень важный компонент. Не стоит его игнорировать.

Оставьте комментарий

Вы должны войти, чтобы оставить свой комментарий.