Да, немаловажная деталька, - рекордер должен генерировать код, который можно (и нужно) читать, редактировать, сохранять в конце концов. В противном случае этот рекордер превращается в лучшем случае в игрушку, которую можно использовать не более как утилиту для демонстрации, проведения демо или создания какого-нибудь продвинутого интерактивного хелпа. Но для тестирования приложений это будет уже бесполезно, хотя бы потому, что при малейшем изменении в интерфейсе или функционале вам придется перезаписать все заново. А это уже не тестирование и уж тем более - не регрессионное.
Если так, то мы попали в главную ловушку автоматизатора. Во-первых, зачем нам внутренние библиотеки приложения? Да, это упрощает жизнь при обмене данными с приложением, например проверке его состояния в процессе выполнения теста. С другой стороны, это не задача UI тестирования. Такие вещи можно и нужно проверять юнит-тестами и не выносить такой сор из избы. Пользователю, которого мы в процессе тестирования интерфейса так рьяно изображаем, абсолютно фиолетово, поменялся ли флажок в методе какого-то там объекта, отнаследованного непонятно от кого, - у него вообще другое представление о том, что такое наследование. Вот ежли у него зеленая кнопка фиолетовая, то ему будет уже не фиолетово (пора отдыхать с такими фразами). Во-вторых, а зачем нам тот же .Net, вот честное слово, не могу представить, зачем в тест-скрипте может понадобиться что-то еще, кроме возможности оперировать элементами пользовательского интерфейса, считывания данных из какого-нибудь репозитария и записи в лог, или еще куда, результатов выполнения теста. Поэтому такая мощь языка и платформы нам не так уж и важна. Кроме уже сказанного, давайте не будем забывать еще и о том, что тестировщики - не программисты. Чем проще и примитивнее язык, тем проще и быстрее с ним разбираться. Но и уже не к ночи упомянутого массива строк-команд тоже "маловато будет".
Я думаю, что лучшим решением для любого инструмента тестирования UI является какой-нибудь скриптовый язык на основе одного из широко известных, например VBScript, JavaScript, Python или AppleScript, причем с минимумом отличий от оригинального, а то и вовсе без каких-либо изменений. Эти языки достаточно простые и достаточно мощные одновременно, для них понаписана прорва документации, библиотек и примеров, они уже известны многим (или очень многим), а это здорово сокращает расходы на обучение.
О, чуть не забыл! По поводу развертывания тестов. Что бы ни говорили, я считаю ,что эта возможность вообще зависит не от интеграции с базовой платформой приложения, а от продуманности и удобства работы самого инструмента тестирования. Так что этот вопрос пока отложим дабы обсудить отдельно.
- кнопка (button)
- список (list box)
- раскрывающийся список (combo box)
- флажок/переключатель (check box)
- радио-кнопка (radio button)
- поле редактирования (textbox, edit field)
- значок (icon)
- панель инструментов (toolbar)
- панель (строка) статуса (status bar)
- всплывающая подсказка (tooltip, hint)
- полоса прокрутки (scrollbar)
- вкладка (tab)
- элемент для отображения табличных данных (grid view)
- меню (menu) (главное меню окна (main menu), контекстное меню (popup menu))
- окно (window) (панель (panel), диалоговое окно (dialog box), модальное окно (modal window))
- дерево — элемент для отображения иерархии (tree view)
Если поиск поделемента мне надо реализовывать самому - это тоже достаточно бедный API. Это не сложно сделать самому, но возникает вопрос: "а чем, собственно, занимались разработчики инструмента". Мало сделать доступ ко всем элементам, надо еще и сделать удобной просмотр и навигацию по дереву графических объектов приложения. Кто пытался, тот знает, как противно вручную двигаться от верхнего элемента-окна к какому-нибудь флажку, в восемнадцатой группе третьей панели седьмой вкладки :)
Еще один пример недостаточной продуманности: очень часто есть необходимость сделать скриншот, скажем, для подтверждения того, что произошло ожидаемое/неожиданное событие, так вот в хорошем API предусмотрена возможность снять скриншот и сохранить его. В принципе, никто не помрет, если прийдется использваться стороннюю утилиту для таких вещей, и это не есть очень важный критерий, но согласитесь, приятно, если о тебе позаботились.
В заключение к вопросу об API, хотелось бы видеть еще одну штуковину, а именно - возможность расширения за счет написания новых и, особенно, использования существующих библиотек. Было бы просто глупостью не использовать всего того, что успели нам во благо насоздавать разработчики ПО.
Еще одна мелочь, хотя и достаточно важная, которую я по своей прихоти отнесу к API, хотя она может быть и сама по себе, - запись и сохранение результатов выполнения тестов. С одной стороны, это может как-то не очень сильно быть связано с API, с другой, если в инструмент встроен логгер, позволяющий создавать отчеты , да еще на уровне используемого скриптового языка и объектов инструмента, да еще с развитой дифференциацией сообщений по типам (issue, debug, error, message etc.) - то ему цены нет.
Первый способ самый привлекательный, хотя и требует достаточно высокой квалификации тестировщика (а возможно, - привлечения разработчиков) и какого-никакого времени, да и не стоит забывать, что инструмент все-таки должен позволять такое расширение своего функционала. Так что этот способ применим далеко не всегда, а иногда бывает так, что если и применим, то овчинка может не стоить выделки.
Второй способ проще, может быть реализован всегда, но он обычно требует наличия внешнего по отношению к инструменту управляющего скрипта (скажем bat-file с командами), который будет запускать инструмент для прогона теста и тушить его каждый раз, когда тест пройден. Второе неудобство состоит в том, что время прогона тестов увеличивается за счет того, что мы тратим время на перезапуск и инициализацию инструмента для каждого теста. Хотя это не так и долго на первый взгляд, но когда тестов много... Тут можно провести аналогию с инструментами для юнит тестинга - возьмите любой тул типа nUnit, поместите каждый тест в отдельный класс и прогоните, а потом перенесите все эти тесты в один тест-класс и посмотрите, как сильно будет отличаться время прогона. По собственному опыту, с 40 минут (это было не совсем юнит, а скорее системное тестирование - так сложилось) время запуска выросло одномоментно до 3 часов, и это на не самом большом тестовом наборе. Без комментариев :)
Раз уж мы заговорили о тестах и тестовых наборах, давайте обсудим еще одну фишку, которая настолько облегчает жизнь, что промолчать о ней сложно. Речь идет о восстановлении состояния приложения после запуска теста. Вообще говоря, есть два подхода в организации тестовых наборов для регрессионного тестирования - последовательный и параллельный.
Последовательный подход заключается в том, что конец одного теста является началом следующего, таким образом, это - зависимые друг от друга тесты и каждый предыдущий тест фактичестки готовит исходные данные для последующего. Этот подход имеет пару преимуществ, заключающихся в том что:
- время прохождения тестового набора сокращается за счет экономии времени на подготовке тестовых данных и реинициализации приложения;
- последовательный тестовый набор, по сути своей, ближе к реальному сценарию действий пользователя, т.к. пользователь обычно работает в "непрерывном потоке сознания" и очень редко заботится о том, чтобы убрать из системы весь созданный им ранее "мусор";
- крайне низкая дефектоустойчивость тестового набора, т.к. "слетание" одного теста в результате возникшей ошибки (что само по себе и неплохо, в виду того, что для поиска дефектов тесты и пишутся) практически гарантированно приведет к ошибкам в последующих тестах набора из-за изменившихся для них начальных данных, хотя с точки зрения тестируемого функционала система в рамках этих тестов работала вполне корректно;
- в случае последовательного набора определение конкретной причины фейла, и как следствие, места пояления дефекта, может быть очень даже нетривиальной задачей.
- инструмент рестартует тестируемое приложение, удаляя/заменяя/перезаписывая данные и настройки (подходит для приложений с четко определенным расположением данных и настроек, например в конфигурационных файлах или базе данных с несложной структурой)
- инструмент запускает промежуточный скрипт, убирающий сделанные изменения (по сути, это такой же скрипт, что и в тестах, просто с утилитарным назначением).
Наконец, последнее обязательное для современных инструментов автотестирования свойство - возможность использования в процессе Continuous Integration (CI). Действительно, сами по себе автоматические (и не только) регрессионные тесты не нужны никому, их задача - своевременное выявление дефектов, вносимых в процессе разработки. Для того, чтобы эти тесты были эффективными, они должны запускаться достаточно часто. Есть правило, говорящее о том, что лучший способ добиться частого и обязательного прогона тестов - включить этот самый прогон в процесс сборки продукта (build). Это не я придумал, это старый и проверенный способ всех гибких методологий, начиная с XP. Вот только работает он для юнит-тестов, а в случае с GUI тестингом есть маленькая поправка-заковыка: т.к. тесты выполняются сравнительно долго (а иногда и совсем не сравнительно :), никто не будет их включать в каждый билд и ждать, пока они все пройдут, - гораздо логичнее создать отдельный билд-план, в который и включить все требуемые тесты. Запускается на исполнение этот тест-план автоматически, обычно по наступлению какого-то заданного времени, скажем, раз в сутки.
На данный момент, единственным, по сути, требованием для использования инструмента в CI является возможность запуска из командной строки с указанием тестируемого приложения и путей к тестам, логам и т.д.
На этом список, пожалуй, можно и закончить. Разве что вспомнить о том, что желательно, чтобы инструмент был совместим с другими, уже используемыми инструментами тестирования и разработки, а также о такой классной штуке, как распределенный запуск тестовых наборов, которая позволяет существенно сократить время выполнения тестов за счет включения в работу нескольких компьютеров, на каждом из которых выполняется часть тестов.
Но без этого, в принципе, можно и обойтись, хотя как знать, когда-то и те вещи, которые я для себя отношу к обязательным, воспринимались не более как просто удобные дополнения :)
В общем, теперь я наконец выдохнул из себя этот список, надеюсь он поможет понять (и мне в том числе) как же именно я выбирал, выбираю и буду выбирать себе тул по душе :)
Следующий пост я снова планирую про Fone Monkey, а там посмотрим...