Показаны сообщения с ярлыком test automation. Показать все сообщения
Показаны сообщения с ярлыком test automation. Показать все сообщения

вторник, 26 февраля 2013 г.

Перезапуск тестов

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

У автоматического теста есть всего один полезный выхлоп - падение теста. Все остальное время автоматические тесты просто греют воздух укрепляя в нас уверенность в нашем продукте (не всегда обоснованную, но это другая история). Это нагревание воздуха, безусловно, полезно для процесса и так далее, но большую часть времени никакой полезной информации не несет. Примерно как ребята в аэропортах, которые могут каждый год рапортовать, что в 100500 проверенных за год пар обуви ни одной бомбы не обнаружено. Работа, безусловно, полезная, но самое крутое что они могут сделать - это, как ни странно, исполнить свое предназначение и найти уже наконец эту чертову бомбу в этих чертовых ботинках. И перезапуск теста это примерно как "ой, кажется у вас в ботинках бомба, пройдите, пожалуйста, повторный досмотр - вдруг мы ошиблись?".

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

И что же означает это падение тестов? Обычно причины две:
  1. Баги в продукте
  2. Нестабильные тесты/Баги в тестах/Нестабильное тестовое окружение
Второе в одной группе, т.к. это, как правило, и является основным объяснением перезапуска тестов. И если мы начинаем перекладывать падение наших тестов на второй пункт, то мы попадаем в страну, где хреновые тесты - это норма, и где-то прячутся баги, которые мы могли бы найти раньше (и мы их, возможно, нашли, но успешно проигнорировали).

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

Да, я понимаю, что у всех своя специфика, уникальный внутренний мир проекта, сроки горят, начальство негодует и KPI не выполняется. Все это может заставить вас игнорировать какие-то упавшие тесты. Как правило это просто пустые отмазки. Как правило, но далеко не всегда.  Но тем не менее не позволяйте нестабильным, хреново написанным тестам становиться нормой. Не делайте нормой нестабильное тестовое окружение. Это все инженерные задачи - они решаются (не всегда легко, но тем не менее решаются). Если, конечно, суть вашей работы не заключается в том, чтобы демонстрировать пару тысяч зеленых квадратиков on commit.

среда, 13 февраля 2013 г.

MBT Начало

Традиционный подход к автоматическим тестам выглядит примерно так - тестописатель изучает тестируемую систему и после этого руками пишет каждый отдельный сценарий для проверки искомой системы. Кто-то может написать тут гордое слово "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".
  • Эйлеризуем полученный граф.
  • Рисуем Эйлеров путь на данном графе.
В принципе можно не напрягаться и просто сделать случайный обход графа. Что примечательно - такая стратегия достаточно устойчива к "парадоксу пестицида". С другой стороны, у любого мало-мальски сложного приложения довольно развесистый граф состояний, на которых можно потратить кучу времени, прежде чем получить хоть какое-то покрытие "случайным обходом".

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

Итого

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

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

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

четверг, 28 июня 2012 г.

Грешки Автоматизатора. Часть 4. Выбор языка

Я как-то давно обещал написать по этому поводу пару строк - исполняю.

Еще ни один стартап не умирал из-за того, что выбрал неправильный дистрибутив Linux - Пол Хаммонд

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

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

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

Собственно главный критерий один - как хорошо лично вы знаете тот или иной язык. Все.

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

Наличие API или хелперов в количестве на том или ином языке - странный аргумент. REST API? Нет вопросов вообще. Хелперы и хуки автоматизации? Если они написаны нормально, то проблем с вызовом быть не должно.

Вы не знаете никаких языков? Учите то, что проще учить - Ruby, Python (это просто пара примеров). Учить Java или еще какие C++ - это путь самурая, но не тот случай когда вам нужно как можно быстрее выучить необходимый минимум (а автоматизация - довольно узкая область, там нужен довольно ограниченный набор) для написания автоматических тестов и тестовой инфраструктуры. Да, какие-то языки было бы неплохо подучить, чтобы набить себе резюме, но это вообще не имеет отношения к выполнению задачи.

вторник, 19 июня 2012 г.

Роботу роботово

Without changing our pattern of thought, we will not be able to solve the problems we created with our current patterns of thought
А. Эйнштейн

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

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

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

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

И как это все обычно делается? Ну мы, "как настоящий пользователь" жмакаем через какой-нибудь Selenium кнопочки и линочки, и все магическим образом проверяется. Выглядит это обычно как-то так:


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

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

Короче говоря - тест этот говно полное, а не тест.

Что мы можем сделать чтобы он перестал быть говном?
  • Убрать лишние телодвижения
    • Никаких сетапов в браузере (мелкий кусок API или хелпер на "создать псто" и мы уже сэкономили кучу сил и энергии)
    • Никакой лишней навигации (хелперы/API на логин и переход к псто... да хоть директ линком в псто)
  • Никаких тестов с сотнями проверок (в идеале один тест - один ассерт)
  • Никаких трешевых тестов
    • CRUD - ок
    • Дешевые проверки на безопасность - ок
    • Основной функционал - ок
    • Выдирание алайнов элементов страницы и их стилей - в другой набор тестов пожалуйста
    • И т.д.
Да, возможно в вашем конкретном случае это будет не реализуемо, потому что никто вам не даст никаких клевых API, никто вас не снабдит классными хелперами забирающимися в потроха приложения. Но не отчаивайтесь - дерьмовое testability в наше время в порядке вещей. А отсутствие хороших хуков в приложение, легкости конфигурирования и смены состояний приложения это оно и есть. Для примера можете попробовать автоматически протестировать мало-мальски сложное мобильное приложение (лучше сразу на symbian чтобы жизнь медом не казалась) - после веба ощущения как-будто вам обе руки отрезали. Тестирование веб-приложения с плохим testability после того как вам показали хорошее - точно те же ощущения. Получается эдакий технический долг перед тестировщиками с которым ваши тестировщики будут жить вечно.

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


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

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

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

суббота, 28 апреля 2012 г.

Baby steps for pussies

В современной разработке ПО сложился ряд практик сильно завязанных на то, чтобы всем было удобно маленькими шажками развивать свой продукт. Agile во многом об этом, TDD/ATDD/BDD об этом, continuous delivery об этом, A/B тесты об этом. Большая часть интернет-гигантов в том или ином виде их практикует. Многие высокотехнологичные стартапы выпустив свой мегапродукт и выжив после этого плавно переходят к управлению рисками через вышеозначенные практики. Ведь это позволяет постоянно совершенствоваться, позволяет сделать так, чтобы от вас были без ума 80% пользователей.

И их всех можно понять - эти практики позволяют довольно быстро и интерактивно дотачивать продукт. Если у вас есть много пользователей, то вы раскатываете на 1% аудитории небольшие правки. Новую анимацию, пяток разных оттенков зеленого для заднего фона, несколько разных текстов для одной и той же кнопки, маленькую новую фичу. А дальше можно просто смотреть что делают пользователи и считать что происходит. Тот вариант, которые приводит к более желательному для вас поведению остается, остальные пропадают и никто о них не вспомнит. Даже те, кто им пользовался - многие просто решат что им показалось. Если вы маленькая контора - просто выкатываете всем и смотрите что происходит. Если все плохо - быстро откатываетесь назад и делаете вид что ничего не случилось. Так дотачивали и дотачивают Facebook, большую часть сервисов Google, Twitter, Etsy, предвыборный сайт Обамы, и еще кучу всего.

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

Но у этого всего есть пара недостатков.

Первое - все эти практики в большинстве своем приводят к тому, что вчерашние стартапы приходят к жизни, в которой нет места большим, революционным изменениям. Сначала вы их боитесь, потом вся ваша инфраструктура, сложившиеся вокруг нее процессы и выросшая из этого всего культура просто не могут позволить себе большие, революционные изменения. Вы подсаживаетесь на эти маленькие экспериментики, ведь это так круто! И вы уже не думаете о больших свершениях. которые нельзя разглядеть через тысячи маленьких коммитов. Мы получаем "более быструю лошадь" вместо автомобиля. Лучшие инженеры мира при поддержке кучи денег работают над тем, чтобы помочь бизнесу решить на сколько пикселей и в какую сторону подвинуть поле ввода, чтобы вся обезличенная ими же масса принесла на 0.1% больше денег. Не обязательно даже понимать почему, достаточно видеть, что да, так будет на 0.1% больше. Маленькие шажки, которые становятся маленькими, но очень тяжелыми кандалами.

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

четверг, 26 апреля 2012 г.

Какая бывает автоматизация? Часть вторая.

Какие бывают инструменты?

Занимаясь автоматизацией большинство регулярно изобретает велосипеды - логгеры, фреймворки, драйверочки, тестовые клиенты. Для особо дорогих и очень типовых велосипедов вроде драйверов (selenium) или раннеров (любой xUnit фреймворк) как правило есть готовые решения. Какие-то бесплатны, как selenium, какие-то так или иначе стоят денег, как практически любой набор тестовых драйверов от Microsoft. Все это фактически и является инструментами автоматизации, которые редко кто пишет сам, так как времени на написание хорошего драйвера для того же браузера уходит порядочно.

Коммерческие инструменты
Если ваши разработчики считают что их инструменты дорогие, то можете показать им расценки на инструменты для автоматизации тестирования. Увы, большая часть коммерческих инструментов по автоматизации тестирования стоит как самолет даже за самую плохонькую лицензию. Второй минус - убийственные схемы лицензирования пришедшие к нам из пазапрошлого века, которые сильно мешают полноценно привлекать других членов команды (разработчиков, администраторов и т.д. и т.п.) к работам по автоматизации.
Остальные проблемы обычны для практически всех коммерческих инструментов (не только для тестирования):
  • Практически невозможно допилить под свои нужды, особенно если ваш поставщщик считает что он точно знает что вам нужно, а чего нет. А в случаях когда это можно вас в лучшем случае ждут боль и страдания.
  • Поставщик инструмента может перестать существовать. Особенно это печально, когда у вас перестает существовать поставщик драйверов к какой-нибудь бурно развивающейся вещи вроде мобильных платформ или браузеров - в этом случае меньше чем через год вы удостоитесь чести унести все ваши труды на помойку без возможности восстановления.
  • Ну и классический vendor lock-in. Как правило поставщики коммерческих инструментов предлагают вам полный комплекс решений в котором, по мнению поставщика, замены ряда кусков (как то continuous integration) быть не может и не должно. Раньше это принимало такие чудовищные формы, как, например, изобретение собственных языков программирования для своих инструментов тестирования. Так же много боли вас может ожидать от попыток интеграции с другими инструментами автоматизации, даже если их аналогов в продуктовой линейке поставщика нет.
Бесплатные инструменты
Их много на любой вкус и цвет, особенно в относительно популярных и развитых технологических областях. Их можно бесплатно использовать, их можно бесплатно допиливать под свои нужды, ими может пользоваться любой член команды, их как правило очень легко интегрировать в другие инструменты (зачастую не во все, но тем не менее), они никога не перестанут существовать, поскольку вы зачастую можете взять их код и сами допилить. Правда у них есть один большой и страшный минус:
  • БОЛЬ И СТРАДАНИЯ ЧЕРЕЗ ОПЕНСОРС. Бывают откровенно чудовищные решения с плохим кодом внутри. И на них, как правило, не написано какое хорошее, а какое нет, особенно если вам приходится браться за не очень популярные инструменты.
Чему учиться?
  1. Учитесь программировать. Желательно на скриптовых языках вроде Python, Ruby, Perl, JavaScript (продолжать можно бесконечно). Вам все равно придется писать скрипты рано или поздно, так что если у вас есть выбор - лучше выбирайте их.
  2. Регулярные выражения. Вам часто приется заниматься разбором больших текстовых выводов в том или ином виде и просто работать с текстом. Увы лучше регулярных выражений для подобных задач пока ничего не придумали. К тому же регулярные выражения +/- универсальные для всех языков.
  3. Если вы занимаетесь автоматизацией веба, то учите xpath и css. У веба большое преимущество перед другими видами автоматизации - доступ до всех элементов иинтерфейса, даже если там внутри мрак и фарш. Пользуйтесь пока есть такое счастье.
  4. SQL (или NoSQL, но это пока сильно реже). Даже если тестируемые вами приложения не используют базы данных (что сейчас редкость), то оно вам пригодится когда вы возьметесь за тестовую инфраструктуру.
  5. Системы контроля версий.
Кто и как обычно разрабатывает автоматические тесты?
Я не буду вдаваться в детали, просто опишу две основные группы. Ни одна из них в вакууме не является плохой или хорошей, просто некоторые вещи в этой жизни случаются и с ними приходится жить.

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

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

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

Автоматизация вместе с разработкой
Как и тестирование параллельно/вместе с разработкой - довольно диковинный зверь в наших краях, увы.

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

пятница, 13 апреля 2012 г.

Какая бывает автоматизация? Часть первая.

Принесли как-то русским мужикам
на лесозаготовках японскую бензопилу.
Мужики положили под пилу здоровую сосну:
- Вжик - сказала пила
- Ого - сказали мужики и положили под пилу лом:
- Др-рр-рр- сказала пила и заглохла
- Ага!!- сказали мужики и пошли валить
лес двуручными пилами.
Вместо предисловия
Сравнительно недавно в голову залетела очередная шальная мысль о том, что написание того как не надо делать ("грешки автоматизатора") это примерно так же плохо как писать о том как надо делать ("лучшие практики"). Поэтому решил начать писать о том как оно вообще бывает.

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

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

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

Record + Playback
Древняя как автоматизация тестирования идея - записать шаги пользователя и потом проигрывать их. До сих пор эти "зайчатки разума" тлеют в разного рода коммерческих приложениях, а так же в некоторых не очень коммерческих (Selenium IDE умеет так делать).

Главные бонусы от такого подхода можно почитать в любой брошюрке к вендорскому софту для автоматизации тестирования:
  • Вообще не надо уметь программировать - тупо записал и тупо проиграл обратно
  • Очень легко создавать тесты, бессмысленные и беспощадные
На этом бонусы заканчиваются и начинаются проблемы:
  • Это не тесты, от слова "совсем". Это просто запись, которую мы можем проиграть и она может сможет проиграться, а может не сможет. Если нам понадобятся какие-то проверки (verification point'ы) или особо умное поведение, то придется допиливать
  • Они как правило записывают не все. Да, возможно у вас будет тот самый случай, когда во всем вашем проекте не будет ни единого контрола/события, которое данный конкретный инструмент не может обработать, но зачастую это не так, поскольку технологии шагают семимильными шагами вперед, а производители софта ддля record'n'replay в большинстве своем за ними не очень поспевают
  • Они отлично ломаются. Изменения в пользовательском интерфейсе как правило позволят вам часто и по-многу пользоваться возможностью легко и непринужденно создавать тесты
  • Их сложно поддерживать. У вас не будет практически ничего что вы могли бы переиспользовать в разных тестах. И если тестов будет очень много, то это + предыдущий пункт принесут вам очень много головной боли
  • Нельзя начать тестировать пока нет готового приложения. Вообще. Никак. Тупо потому что нечего записывать
Идея в общем отличная, но, как видим, совсем не годится для масштабной автоматизации и длительных проектов.

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

Отсюда появляются новые плюсы и минусы. Собственно плюсы:
  • Бесплатно. Мы можем взять любой скриптовый язык и начать фигачить тесты
  • Гибко. Нас не ограничивают возможности записывающего софта и создаваемые им структуры
  • Быстро. Не так быстро как просто record'n'replay, но все еще быстро, т.к. просто берем и пишем какой нам вздумается тестовый говнокод в меру наших способностей
И есть набор суровых, непреодолимых для ряда людей/контор препятствий:
  • Надо писать код. Хотя бы как-нибудь. Хотя бы фиговый код. Но надо
  • Они все еще хрупкие. Мы же ничего принципиально нового не придумали, так что проблема с хрупкостью никуда не делась
  • Сложно поддерживать. См. предыдущий пункт
Нормальный подход для небольших и простых задач, но все еще никуда не годится если мы планируем какие-то масштабные проекты по автоматизации.

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

От такого подхода у нас появляется волшебная шляпа и +10000 к ловкости еще одна куча бонусов:
  • Мы наконец-то можем переиспользовать код. Написание новых тестов работающих по уже описанной в тестовых библиотеках функциональности сускоряется в сотни раз
  • Легко поддерживать. Нам теперь не надо перелопачивать тысячи скриптов при изменениях тестируемого приложения, а требуется всего-то починить пару-тройку мест в тестовых библиотечках. Правда это все при условии, что мы не наделали ошибок при попытке структуризовать все наше богатство
  • Писать тестовые библиотечки просто. Не нужно иметь за плечами годы опыта программирования чтобы понять что же написано в тестах, а так же написать свои. Да и с библиотечками, как правило, ничего сложного нет. Опять же - если написать тонны говнокода то этот бонус превращается в тыкву, а мы отправляемся читать про бонусы и минусы предыдущего подхода
Из этих бонусов вытекают логичные минусы:
  • Нельзя взять и начать писать тесты. Нужно сколько-то усилий потратить на написание тестовых библиотечек и все еще нужно уметь программировать
  • Сильно новые тесты требуют расширения тестовых библиотечек. Т.е. придется думать над структурами, писать местами сложный код и так далее
  • Тестовые данные так или иначе вшиты в скрипты, так что для их правки и написания новых опять придется программировать
Метод нормально работает для простых задач. С масштабной автоматизацией возникают проблемы, если кто-то кому надо понимать что же делают тесты не умеет программировать. Да и вообще для не умеющих писать хоть какой-то код метод никуда не годится.

Data-/Keyword-Driven скрипты
Мы просто выносим непосредственно тесты в какой-то мало-мальски пригодный для не умеющего программировать пользователя вид и пишем набор скриптов или полноценный фреймворк, который умеет генерировать из этого автоматические тесты. Делается это все с простыми целями:
  • Не умеющие программировать пользователи смогут писать тесты
  • Мы можем поопилить поддержку автоматических тестов. Не умеющие программировать правят сами тесты, умеющие программировать правят и развивают все что под ними
  • Легко поддерживать и есть куча кода для переиспользования. Т.к. у нас там все же какая-то модульная структура внутри есть
Правда все становится сложнее, из-за чего возникают следующие проблемы:
  • Очень много работы. Для keyword-driven варианта, конечно, есть куча опенсорсных BDD фреймворков, но не для всех
  • Придется допиливать. Время от времени будут возникать хотелки не предусмотренные текущей реализацией и всю эту машинерию придется перепиливать. А для этого нужны будут люди способные в ней разобраться и время
В целом иногда мы можем использовать бесплатные решения. Эти подходы хороши для масштабной автоматизации, но все равно понадобятся люди способные программировать. Для простых задач городить весь этот огород как правило не имеет смысла.

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

Часто приходится иметь дело с графическими интерфейсами, т.к. начальство/заказчик/мы хотим "чтобы как пользователь так по экранчику жмакать". Собственно с ними и возникает больше всего проблем, потому что:

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

Можно тестировать под графическим интерфейсом, т.к. здоровый кусок бизнес-логики именно там. Тесты будут быстрее и надежнее, но не смогут полноценно заменить собой тесты через гуй, т.к.:
  • Графические интерфейсы как правило уже привязаны к бизнес-логике и привязанны корректно, а под ними нас зачастую ждет сложное месиво в котором придется еще и разбираться.
  • Зачастую на графических интерфейсах имеется какая-то функциональность, которая никак больше недоступна.
  • У людей бывает паранойя и им хочется чтобы все было как взаправду, "чтобы как пользователь так по экранчику жмакать". В ряде случаев быстрее сделать чем спорить. Да, вариант плохой, но понять что это плохо в ряде случаев очень сложно.
Если последним пунктом вас никто не пытает, то оптимальным вариантом было бы покрытие основной функциональности под графческим интерфейсом и сравнительно небольшой (не обязательно автоматизированный) набор end-to-end тестов для морды.

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

Продолжение следует...

пятница, 6 апреля 2012 г.

Суть автоматизации регрессионного тестирования

Переиначивая копипасты коллективным разумом:

Ты СОВЕРШЕННО не понимаешь в чем суть автоматизации регрессионного тестирования. Это не «о, привет чуваки, зацените какой пиздатый способ повысить качество я нашел в интернете, гыгы». Автоматизация регрессионного тестирования - это не псевдоинтеллектуальный TDD. Автоматизация регрессионного тестирования - это не краудсорсинг, бетатесты или подглядывание за конкурентами. Автоматизация регрессионного тестирования это образ, рассматривая который, инженеры контроля качества могут представить себя в гугле — милыми, беззащитными, сопереживающими миллионерами, которыми они якобы являются. Zynga купила себе Draw Something, а мы смеемся. MS запустил Mango, а мы смеемся. Twitter пропускает сообщения в выдаче, а мы обсуждаем и просим еще. Самоубийства, убийства, геноцид — мы автоматизируем регрессию. Расизм, сексизм, дискриминация, ксенофобия, изнасилования, беспричинная ненависть — мы автоматизируем регрессию. Клиенты разбегаются и перестали выплачивать зарплату — мы автоматизируем регрессию. Мы бездушно подпишемся под чем угодно, наши предпочтения не основаны на здравом смысле, автоматизация регрессии без гарантий и обязательств — наша стихия, мы — истинное лицо рынка контроля качества.

суббота, 17 марта 2012 г.

Еще раз про Automation Bias: TDD, BDD и роющие осы

Вместо предисловия

Это Сфекс:

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

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

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

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

Увы, люди тоже порой уподобляются Сфексам.



А теперь про TDD и BDD

BDD - прекрасный, местами даже изумительный инструмент. Писать тесты человеческим языком это безумно круто, пока вы не наткнетесь на ограничения в выразительных средствах. Человеческий язык все же сильно богаче, чем имеющиеся фикстуры, сколь бы много вы их не написали. В итоге совершенно конские усилия начинают тратиться на написание фикстур для прикладывания усложненного, псевдонатурального языка тестов к настоящему API этих самых тестов. Брайан Марик нашел замечательнейший пример сложной конструкции в BDD:
Feature: Purchase Items in Cart

  Scenario: Using Existing Billing and Shipping Information
    
    Given I have an existing account
    And I have previously specified default payment options
    And I have previously specified default shipping options
    And I have an item in my shopping cart

    When I sign in to my account
    And I choose to check out

    Then I see my order summary
    And I see that my default payment options will be used
    And I see that my default shipping options will be used

Example taken from http://johnwilger.com/blog/2012/01/21/acceptance-and-integration-testing-with-kookaburra/
 Сложный, не очень читабельный тест, который в той же статье предлагают писать вот так:
describe "Purchase Items in Cart" do
  example "Using Existing Billing and Shipping Information" do
    given.existing_account(:my_account)
    given.default_payment_options_specified_for(:my_account)
    given.default_shipping_options_specified_for(:my_account)
    given.an_item_in_my_shopping_cart(:my_account)

    ui.sign_in(:my_account)
    ui.choose_to_check_out

    ui.order_summary.should be_visible
    ui.order_summary.payment_options.should be_account_default_options
    ui.order_summary.shipping_options.should be_account_default_options
  end
end

# Example taken from http://johnwilger.com/blog/2012/01/21/acceptance-and-integration-testing-with-kookaburra/
Уже больше похоже на unit тесты, больше укладывается в нормальный процесс работы того же программиста. Можно еще меньше маяться дурью и написать тест простым кодом. Да, его будет сложнее показывать заказчику/бизнесу, но и в сложных примерах приведенных выше он все равно нихрена не поймет, а лишних усилий они будут кушать много.

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

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

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

вторник, 13 марта 2012 г.

Баги в наших тестах

Дерьмо случается. Ничего совершенного не существует. Все люди ошибаются. Иначе у нас бы небыло нашей работы.
При этом мы (тестировщики/тестеры/вставьтечтонравится) совсем не исключение.
И когда это случается, то ощущения получаются примерно такие:
Источники таких факапов можно грубо раскидать на три группы:
  1. Факап при реализации. Т.е. действия, совершаемые тестировщиком/его скриптом во время теста неправильные. В скрипте пропустили шаг. Ручками забыли кликнуть. Или сделали лишний шаг/кликнули лишний раз. Наконец просто говнотесты вроде AssertTrue(True).
  2. Факап при интерпретации. False negative/positive практически, только у них причины могут быть разными, а в данную группу мы отнесем именно ошибки толкования правильного результата. Это не только проблема автоматизации. Когда мы выполняем тесты ручками такое тоже может случиться.
  3. Факап в предпосылках. Кривые библиотеки используемые в автоматических тестах, ошибки спецификации, ошибки во время дизайна. Продолжать можно бесконечно. Все это может случиться и, будучи пропущенным на стадии работы с библиотечками/спекой/дизайном, грозит нам ошибками в самих тестах.
В лучшем случае пораженный тараканами тест даст нам false positive. Т.е. мы будем ожидать, что тест должен пройти, получим провал и начнем разбираться. Возможно это приведет к тому, что в процесса разбора завалов тест будет проанализирован, пересмотрен и поправлен. Только (внимание!) никто на не гарантирует что новый тест будет без багов. Не важно делаем мы его руками или это автоматический тест - от регрессии он не застрахован, ровно как и все остальное.

В худшем случае мы получим false negative и никаких оснований подозревать бажный тест в плохой работе у нас не будет. Ну пока исполнитель теста не заметит что тест-то бажный или не случится какая-нибудь катастрофа.

И нет серебрянной пули (если есть - скажите мне пожалуйста!), чтобы этих проблем избежать.

Автоматические тесты не помогут потому, что:
  • Единожды сломанный автоматический тест так и будет оставаться сломанным, пока не случится что-то чтобы мы начали подозревать, что тест с багами. 
  • Да, автоматическими тестами проще работать с false positive, но от регрессий никто не застрахован. 
  • В результате непрерывного, длительного повторения баги, которые упорно отказываются находить наши бажные автоматические тесты, могут расти и пухнуть.

Ручные тесты не помогут потому, что:
  • У людей, как правило, не идеальная память. Есть пресловутая "естесвенная девиация", которая может принести пользу в обнаружении вещей, которые автоматический скрипт обнаружить не способен. Например false negative в случае автомата рискует быть постоянным, а в случае ручного исполнения есть какой-то шанс его все же обнаружить. Но у нее есть и обратная сторона - у нас всегда есть риск "естественной девиации" в интерпритации результатов, например.
  • Иногда очень сложно отловить false positive, допущенный в ручном тесте, так как процесс работы с ними несколько другой. Автоматический тест падает и мы идем разбираться что случилось. Ручной тест показал что все плохо - скорее всего мы уже поразбирались.
То есть проблема эта лежит не в плоскости автоматический/не автоматический тест.

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

понедельник, 6 февраля 2012 г.

Грешки Автоматизатора. Часть 3. Xpath головного мозга

На этот раз пишу с привязкой к инструменту. И инструмент этот (СЮРПРИЗ!!!) - Selenium-WebDriver (дальше просто Selenium или Se).

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

  • Задать много идентификаторов для одного элемента
  • Использовать все возможные идентификаторы тегов (title, например)
  • Обращаться напрямую к индексу элемента
  • Различать элементы по типам (привет findElement!)
Одной невозможности обращаться к элементу по его имени (title) и по индексу уже достаточно чтобы плакать кровавыми слезами.

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

Я долго думал почему же css-локаторы лучше чем xpath, но в итоге не придумал ни одного железобетонного аргумента.

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

Я мог бы сказать, что CSS читабельней чем xpath. Но это вкусовщина. Если человек привык писать //div[@id='eid'], то div#eid для него может показаться ущербным.

Я мог бы сказать, что CSS это практически jQuerry, но автоматизатору со средней полосы до jQuerry как правило нет никакого дела.

Но больше всего раздражает в xpath-локаторах то, что люди пытаются делать вот такие вещи:

html/body/div[2]/div[2]/div/div/ul/li[2]/div/img
//div[@id='ui-datepicker-div']/div/div/select[2]
Только xpath тут совсем ни при чем. Огромная, зловонная куча таких вырвиглазных примеров локаторов на xpath скорее всего существует только потому, что CSS-локаторы штука относительно новая и применяя их не успели еще создать столько мусора. Это просто гипотеза, но справедливости ради стоит заметить, что вырвиглазные примеры css-локаторов я тоже вижу, но в разы реже.

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

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

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

Или проставьте их сами.

Только не рисуйте бессмысленных и беспощадных локаторов. Это зло, которое вам потом придется переписывать. И если у вас нет никакой возможности это зло побороть - переписывать, скорее всего, придется много и часто. И если смену имени/id элемента еще можно быстренько поправить (хотя в частой их смене тоже нет ничего хорошего), то переписывать развесистые локаторы, где упоминается добрая половина элементов DOM-дерева, сильно дольше. А уж читать эти развесистые локаторы после вас...

четверг, 12 января 2012 г.

Грешки Автоматизатора. Часть 2. Sucker Punch Effect

Для не шпрехающих по англицки:
Sucker punch - запрещенный удар (удар исподтишка)
Самый тривиальный пример такого удара можно назвать "смотри, птичка!". Работает так же, как и называется:

  1. Говорим "смотри, птичка" явно указывая, что птичка где-то в стороне.
  2. Когда противник отвлекается - бьем его в лицо.
Чаще работает в случае дружеских мордобоев. Это я не сам придумал, это за меня посчитали психологи в ходе свои бесчеловечных экспериментов.

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

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

Увы, у этого костыля есть ряд побочных эффектов.

Первый, и самый главный - если у нас в голове дерьмо, то костыль тут ничем не поможет. Даже если вы начнете делать все это дерьмо в 1000 раз быстрее, золотом оно от этого не станет. Оно просто станет очень быстрым дерьмом. Как это лечить, и что нужно делать - тема долгая и отдельная. Первая часть "грешков" была лишь об одном из тысяч аспектов.

Второй побочный эффект - мы начинаем этому костылю верить. А он нас начинает бить. Причем чем меньше мы о нем знаем, тем больнее он бьет.

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

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

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

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

Еще опаснее, если под этот проприетарный тестовый софт вам придется подстраиваться всем продуктом.

Итого. Вернемся к исходной позиции.

Есть мы. Мы пишем тесты.
Есть тесты. Хорошие, автоматические тесты. Будем считать, что тут никаких проблем нет, иначе все станет сильно сложно.
Есть наш любимый костыль. Наш инструмент. Мы в него верим.

И этот наш инструмент, наш друг, бьет нас в лицо. Нагло обманывает, так сказать. А мы об этом догадаемся когда будет уже поздно. Самый натуральный sucker punch.

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

И как тестировщик добавлю - софта к которому у меня нет претензий я еще не видел. Инструменты тестирования не исключение.

среда, 16 ноября 2011 г.

Грешки Автоматизатора. Часть 1 и, думаю, не последняя

Не автоматизируйте thirdparty компоненты.

Каждый раз, когда вы пишите автоматический тест на проверку thirdparty компонент, умирает пушистый котенок.

Нет, ну серьезно, зачем писать автоматические тесты проверку получения почты через GMail-морду? Или виджеты типа кнопочки like? Зачем писать автоматические тесты на проверку thirparty процессора кредитных карт? Зачем писать автоматические тесты на авторизацию вашего приложения через твиттер?

Даже не так.

Что вы хотите узнать?

Если GMail перестанет работать, то вы с этим ничего не поделаете. А ваш тест свалится.
Если банк не проведет платеж через кредитную карту, то что вам это даст? Вы узнаете много нового о своем приложении?
А если платеж где-нибудь зависнет? Вы сможете из теста автоматически узнать, где там в банке завис ваш платеж? А сколько ваш тест готов будет ждать? Час? День? Неделю? Или нужно ставить тест в зависимость от состояния счета?
Вы действительно хотите, чтобы ваши тесты зависели, скажем, от того, упадет ли сеть в Берлине? Или получить кучу ложных срабатываний из-за того, что заглючило корпоративную прокси и у вас не открылось окошко твиттера на авторизацию приложения?

Нет.

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

Делая это вы убиваете котят.

Всегда есть решения проще, к тому же не пахнущие плохим дизайном тестов.
  • Можно проверить почту через POP/IMAP напрямую, используя библиотеки доступные в вашем языке (а они есть почти наверняка)
  • Можно вставить свич и фактически замокировать thirdparty компоненту. Если это сделать аккуратно, то с точки зрения вашего приложения ничего не изменится. Правда тут есть риск выкатить не с тем свичом на продакшен, если деплой у вас идет ручками (в простанородье - "handjob")
  • Можно забраться в базу скриптом и там сделать нужные переключения
У всех этих решений будет пара общих свойств:
  1. Ни одно решение не ставит вас в зависимость от погоды в Ирландии.
  2. Все решения могут сильно ускорить выполнение автоматических проверок.
И это даже не все возможные решения. Можно придумать еще.



На этом с первым грешком автоматизатора все.

Не убивайте котят - пишите хорошие тесты.

пятница, 28 октября 2011 г.

Качество умерло, да здравствует качество

Качество умерло.

Собственно оно никогда и не являлось самоцелью для бизнеса. Конкурентным преимуществом? Да. Самоцелью? Маловероятно.

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

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

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

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

TDD, мониторинг, хорошая обработка ошибок, атомарные функциональные проверки, местами избыточные, где функционал критичен. То, что Julian Harthy называет Productivity Tests - все это работает на то, чтобы разработчикам просто было сложнее чекинить плохой код и чтобы было легко обнаружить и локализировать (testability в экстремуме, практически). Если нет плохого кода и основная функциональность более или менее работает, то при возможности выкатывать на все свои сервера исправления чуть ли не каждые 10 минут реагировать на проблемы пользователя становится сильно проще. И потери от ошибок резко падают.

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

Виттакер и Ко. предлагают в связи с этим совсем избавиться от тестировщика в виде человека выполняющего black box тесты дни и ночи напролет. С их точки зрения имеет смысл или зарываться в глубокую специализацию (UX, производительность, Productivity тесты), или заниматься тестированием фактически на уровне требований, когда критично понять правильной ли мы дорогой идем, и что же тут делать. При этом часть специализаций вроде нагрузочных тестов и функциональщину они хоронят за крауддсорсингом и облаками. Спорно, но Google такой Google... как всегда, в общем-то.

Правда они не так громко говорят, что такая модель работает далеко не для всего софта, и что процессы ОК от силы у 10% команд. Более того - по тем же Productivity тестам есть куча софта и фреймворков в открытом доступе, но практически нигде не написано как писать, что искать, и насколько те или иные подходы оправданы.

У них качество умерло.

Кто пользовался гуглосервисами - поймет. Кто не понимает - можно вспомнить случившиуюся в начале этого года потерю гмейлом почты у 150 тысяч пользователей, или потрахаться с blogger.com (про рекламу пива на детских каналах в ютубе мы умолчим). Или факапы с биллингом у МТС. Или регулярные проблеммы фэйсбука с приватностью (тысячи их). Или то, что твиттер это довольно поганенький в плане качества сервис, который регулярно падает и если бы он был IM, то умер бы в агонии давным давно. Но он не IM, и его фиговую способность справляться с бешенно растущими нагрузками нам компенсируют тем, что все это очень быстро чинится.
И это не только там, где с процессом все хорошо и риски у пользователей сравнительно невелики. Банковский софт который мне встречался, это, наверное, самое отвратное с чем мне приходилось работать как конечному пользователю.
Пользователя в принципе не так сильно раздражают проблеммы, если он может быстро от них избавиться. А вот если его игнорируют - его это раздражает куда больше.

Но есть сферы применения тестирования, в которых оно приносит, или может приносить вполне очевидную, реальную пользу:
  • Можно создавать умные системные тесты, которые при правильном применении приносят много пользы, но при этом достаточно сложны в разработке.
  • Можно работать над обнаружением сложных проблем, вроде работы с большими и сложными структурами данных и анализа проблем на продакшене.
  • Нагрузочное тестирование это вообще очевидный профит для бизнеса, т.к. помогает корректно расходовать деньги на софт и железо.
  • Исследовательские навыки и умение задавать правильные вопросы. Это то о чем постоянно пишет Болтон и то, что все же упоминает Виттакер (хотя и в другом виде).
Добавим немного из примеров очевидно полезного тестирования от Виттакера:
  • Productivity тесты и прочая работа "на процесс".
  • Специализация а-ля UX, производительность.
  • Тестирование документации (хардкорная такая аналитика)
При этом старый, архаичный процесс с тяжелой бюрократией и размытыми объяснениями отдающими параноидальным бредом вызывает вопросы насчет своей пользы для бизнеса уже сейчас. Кто-то жалуется, что не понимает что вообще там в их тестировании происходит, кто-то говорит, что оно пустая трата денег и очень тормозит процесс. Ему грозит стать таким же рудиментом, как IE6 в корпоративных стандартах (нет, этот рудимент все еще приносит деньги, но он где-то далеко в пятой точке технологического прогресса).

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

И еще раз процитирую Вейнберга: "Тестирование - это поиск информации с целью обеспечить ею принимаемые решения".
Очень сложно принимать какие-то своевременные решения, когда тебе создают 100500 багов, которые толком не объясняют где проблема, в чем проблема, а просто сообщают, что проблемма есть и сеют панику. Очень сложно принимать решения на основе тонн документации (и где они нашли на это время?) сомнительной полезности и нулевой прозрачности для Менеджера (нет, ну тестировщик-то написал и сам разберется, да... а нафига?).

Вейнберг дает такое определение качеству: "Качество - это то, что важно для кого-то". Надо знать этого кого-то. Надо понимать, что важно.

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

пятница, 14 октября 2011 г.

Тестовые оракулы в автоматизации тестирования

"In testing, an oracle is a heuristic principle or mechanism by which we recognize a problem"
"The Cooking Detector", Майкл Болтон  

Основная причина выбора этой темы - то что автоматизация тестовых оракулов это половина пути к автоматизации исследовательского тестирования вообще и (FS)MBT в частности.

Собственно что это такое и с чем его варить?
Рассмотрим старую добрую IPO (input-process-output) модель. На выходе мы даем какие-то данные, сгенеренные волшебным образом (в контексте данного топика это не важно, тем более литературы по этому сильно больше чем по оракулам), а на выходе получаем какой-то результат который нужно интерпретировать.

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

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

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

Тут встает вторая проблема - а как мы поймем по входному значению какой именно код ошибки должен выйти?
Вариантов море:
  • Подавать на вход только те значения которые обязательно вызовут нужный нам код ошибки. Это частично можно приравнять к хардкоженным значениям и, по сути, хардкоженному оракулу. Такой вариант оракула очень не гибкий и по сути статичен, что не позволит его использовать для поиска багов, но он может послужить неплохой сигнализацией.
  • Мы можем статистически накопить себе информацию о том, как на определенных данных должна реагировать SUT. Т.е. подавать на вход в разных случаях какие-то классы значений, а на выходе получать код ошибки. Если для N предыдущих запусков выдавался один результат, а на N+1 получился другой - сигналим FAIL теста. Если N+1 результат по итогам ручной проверки оказался правильнее чем результат на N - правим ручками и фактически сводим к предыдущему примеру. Это тоже хороший способ сигнализировать об изменениях, немного чреватый ложными провалами (и ложными успехами, в случае, если у нас в первых прогонах были неизвестные нам ошибки), но зато покрывающий огромные объемы данных и чуть более гибкий чем предыдущий вариант (что расширяет возможности его использования). Как пример использования такого оракула можно привесим регрессионные тесты (и еще одна причина почему они не находят ошибки).
  • Мы можем независимо от SUT генерировать на основе входных данных ожидаемые результаты. Причем учитывая что мы пишем тесты, а не полноценный продукт - заморачиваться на оптимизацию алгоритмов генерации ожидаемого результата нужно только в том случае, если нам нужно прогнать много и быстро. Это сложный оракул, но он позволяет в теории обрабатывать огромные объемы данных и сам их сопоставлять. Как и любой сложный оракул он дополнительно вносит риск дефектов в его реализации. Но зато и отдача при правильном использовании такого оракула может быть просто огромной.
  • И еще 100500 вариантов
Самое важное тут то, что сам по себе механизм верификации результатов теста является логически совершенно отдельной сущностью. Его даже не обязательно включать в скрипт, который занимается прогоном выходных данных по SUT. Более того - мы можем сами результаты тестов (не бинарная логика вида PASS/FAIL, а реальные результаты, т.е. output) хранить где-то и уже постфактум прогонять по ним новые и новые оракулы. Мы можем честно запихать все это добро в механизм обхода (и генерации) модели SUT и получить себе полноценный MBT.

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

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

Так, например, входными данными теста являются:
  1. Изначальное состояние SUT
  2. Состояние окружающей SUT среды
  3. Любые предусловия которые привели к данному состоянию или к дданному input'у
  4. Собственно input данные
  5. ...
  6. Придумайте еще 100500 вариантов (а они есть)
Выходные данные это:
  1. Конечное состояние SUT
  2. Состояние окружающей SUT сред после выполнения Process части теста
  3. Выходные данные
  4. Любые данные сгенерированные SUT, кроме тех, что мы ожидаем для данных входных данных
  5. ...
  6. Другое
Обработку данных так же можно разбить на части. И все это так или иначе может быть использовано в наших оракулах для получения более достоверной оценки и/или более интересных, с точки зрения тестирования, результатов.

Но мы можем пойти еще дальше и отказаться вообще от этой IPO-like модели. Например мы можем сосредоточиться только на output части и по ней определять что происходит успех или нет. Мониторинг серверов с автоопределением критичности/некритичности состояния это хороший пример таких оракулов. Собственно критерии по которым мы определяем хорошо или плохо серверу это и есть своего рода оракул.


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