пятница, 25 сентября 2009 г.

Правила написания скриптов автотестов (TestComplete)

В дополнение к предыдущему посту, и для совместного (параллельного) использования этих постов.
Обращаю сразу внимание, что правила в этом посте специфичны для конкретного проекта, конкретной организации и конкретных инструментов автоматизации и тестирования вообще. Поэтому основные мысли уловить можно, но перед использованием в других проектах\компаниях эти правила следует заточить под свою спецтфику. У нас инструмент автотестрования- TestComplete 6.52. Багтрекинг - TFS. ОС- Vista, WinSserv2003, WinSserv2008. Виртуализация- VMWare. MS VisualStudio2008.
Итак сами правила:

1. Правила создания тест кейсов. Без комментариев :)

2. Инструкция к тесткомплиту. Без комментариев :) Хорошо, что есть на русском и на английских языках.

3. Структура: нумерация и название ТС, идентичны ручным ТС. Иначе не поймешь, что проверяет тот или иной скрипт.

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

5. Структура: первый проект (ТС) содержит скрипт (назовем его "Reference"), содержащий функции и методы, испотльзуемые в других ТС. Тут следует прокомментировать: оптимальным вариантом представлялось такая организация- тест кейс=проект (project) тесткомплита, набор тест кейсов=(project suite) съют. сам скрипт (script)= набор функций (function).
Каждый ТС (проект) содержит несколько скриптов: Первый- ссылка на скрипт "Reference" первого проекта.

6. Структура: первый проект (ТС) содержит скрипт ("Reference"), содержащий функции и методы, используемые в других ТС.

7. Структура: остальные ТС (все кроме первого) содержат основные скрипты ТСа ("Main" и "Local _Reference"), и "ссылку" на скрипт ("Reference") скрипт (выглядит эта ссылка просто как скрипт). Таким образом у нас имеется 3 скриптовых элемента в каждом проекте: 1)одно хранилище ("Reference") функций и методов, используемых в различных скриптах, находящееся (физически) в первом проекте и вызываемое из других проектов (ссылки); 2)"Main" скрипт в каждом проекте, в котором находятся наборы функций, необходимых для выполнения тест кейса; и 3)"Local _Reference" скрипт, в котором находятся "локальные" функции, которые сделаны для того, чтобы не загромождать "Main" скрипт, облегчать процесс "понимания" скрипта, облегчать модификацию и т.д. Поясню зачем это нужно: при выполнении тестирования часто приходится повторять одни и те же действия по многу раз. Ясно, что иметь одинаковое описание этих действий (функцию или ее часть) во множестве скриптов совершенно неэффективно, тем более подумайте о процессе модификации такой функции при необходимости. Поэтому эта функция выносится в отдельное место (скрипт "Reference", или вообще в отдельную библиотеку, но пока не будем усложнять) и вызывается при необходимости. Таким образом, когда нужно будет исправить скрипт в этом месте работы, мы правим только одну вызываемую функцию и все. Далее: основной скрипт проекта ("Main") содержит основные функции проверки- например, 3 штуки: открыть форму, внести изменения, сохранить. Логично предположить, что 1 и 3 действия будут проделываться многократно при тестировании (хотя я заносил в скрипт "Reference" функции уже при однократном повторении). Поэтому выносим их. 2 действие выносить смысла нет, так как, допустим!, вносим какие-то уникальные изменения, для данной конкретной проверки.
Однако расписывать эту функцию прямо в мейн скрипте не стоит- потом сложно будет разбираться в этом нагромождении (как правило функции содержат в себе множество вызовов других функций). Поэтому выносим ее в скрипт "Local _Reference".

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

9. Структура: все функции и методы должны иметь уникальные имена. В скрипте функций ("Reference")- "говорящее название" (например, function DeleteChildClass()). в основном скрипте ("Main")- неполный номер ТС после названия функции. (например, function DeleteChildClass11231(), где А0011231- номер ТС). Это нужно для того, чтобы не путать фукнкции из "Local _Reference" и "Reference" скриптов. А это возможно, потому что один скрипт может содержать в себе одинаковые проверки, но с, допустим, различными данными: в одном случае это будет стандартная проверка (вызов из "Reference"), в другом- специфическая (вызов из "Local _Reference"). Действия почти одни и те же, имена функций похожи, но обязаны различаться.

10. В функции первым комментом должно идти описание того, что эта функция делает. (например, "// Создание "testclass""). Чтобы не ломать голову читая сам скрипт.

11. В "Main" скрипте также должно быть описание того, что этот ТС делает ("// создание класса ").

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

13. Все функции должны иметь структуру "try-catch". Весь набор скриптов не должен останавливаться при выпадании исключения приложения.

14. Скрипт должен быть написан в соответствии с ручным ТС. То есть с выделением и обозначением шагов (групп шагов), предустановок и постустановок. (допускается copy\paste описания шага из ручного ТС).

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

16. Функции в скрипте должны быть разграничены: "\\***". Просто для облегчения восприятия. Отлично работает "сворачивание".

17. Скрипт должен безопасно работать с приложением (метод "terminate()" недопустим в обычных тестах).

18. Верификация "внешнего" вида (GUI) должна быть сведена к минимуму. Тестирование основано на описании состояний системы.

19. Чем большее количество свойств системы верифицируется- тем лучше

20. Необходимо учитывать связанность выполнения съюта тесткомплитом. тем не менее должна быть возможность собирания отдельных съютов для тестирования тех или иных задач.

21. Обращение к процессам и их объектам должно осуществляться через переменные ("w1 = p1.QAdminForm; w2 = w1.treeViewClass;").

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

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

24. Все имена объектов и значения свойств, используемых в методах и функциях- из Object Brouser Тestcomplete методом copy\paste. Так как не все символы видимы в Object Brouser. (такие как пробел). Хотя тут нужно пинать разработчиков.

25. Координатный клик допустим только в исключительных случаях.

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

27. BuiltIn.Delay() допустим только в исключительных случаях. Пользуемся методами Wait...

28. В названии объекта (к которому обрщаемся) должно быть указано максимальное количество постоянных неизменяемых символов. Есть вероятность появления похожих по названию объектов.

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

30. При удалении, модификации объектов метаданных, должна быть проведена дополнительная верификация работы с "нужным" объектом, где должны отразиться эти изменения (сугубо специфично).

31. При блокировке выполнения скрипта, в лог должна отправляться ошибка с указанием номера бага.

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

33. Все новые скрипты должны добавляться в VSS (потом TFS). в конце дня- check in.

34. Приоритеты: сначала поддержка скриптов в актуальном состоянии, потом - создание новых скриптов.

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

36. При "ссылочном" методе поиска функции, в которую необходимо внести изменения- необходимо убедиться в ее неактуальности; в том, что именно в нее должны быть внесени изменения.

37. copy\paste кода скрипта недопустим! скорость создания скриптов обеспечивается использованием уже написанных функций, а не копированием кода.

38. Допускается клонирование проектов, с незамедлительным внесением изменений в названия проекта, скриптов, функций, объектов и код скриптов. Рабочий скрипт (если таковой присутствует необходимо очищать от старого скопированного кода). Добавление новых проектов или элементов проектов к TFS- только после внесения описанных выше изменений.

39. Все дополнительные приложения, вызываемые из скрипта, должны быть приведены к общему виду (например, во весь экран, масштаб 100%), а затем сравнены с эталоном.

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

41. Лучше чаще использовать возможности Object Brouser (свойства и методы), чем Recorder.

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

43. Скрипт должен отправлять в лог такие сообщения\ошибки, чтобы были понятны причина возникновения исключения и его "местоположение" (во время выполнения). То есть, если, например, сравниваются свойства какого-либо объекта, и какое-то свойство имеет значение, не соответствующее ожидаемому, то сначала в лог должна отправиться ошибка с указанием на различие, а потом уже автоматическая ошибка, что ТС fails.

44. Структура скрипта должна предусматривать возможность запуска и выполнения скрипта под различными ОС (XP, Vista, Serv 03, 08) (первоначально- Vista и XP); То есть методы и функции должны быть написаны с учетов всех соответствующих различий в ОСах- необходимо максимально стремиться к унификации функций относительно различных ОС, в тех случаях, где это невозможно- должны быть написаны различные функции под все необходимые ОС, и взависимости от вида ОС, должны выбираться те или иные функции, методы, переменные и т.д.

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

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

47. При выборе объектов, например, в дереве (tree) должен использоваться метод Select(), а не Click() там, где это возможно.

48. Необходимо учитывать, что на разных ОСях, на виртуалках и при удаленном доступе могут быть задержки выполнения скрипта. Поэтому необходимо использовать "Wait*" методы при написании скрипта там, где это возможно.

Как-то так. Хотя подозреваю, что большинство пунктов необходимо комментировать дополнительно, объясняя суть, необходимость использования. Подождем уточненной статистики..