пятница, 11 октября 2013 г.

Как быстрее проверять автотесты во время их разработки

    Ни для кого не секрет, что процесс выполнения UI автотестов не очень быстрый. А во время создания автотеста часто приходится запускать его на выполнение несколько раз и ждать, пока он пройдет. В целях экономии времени я использую несколько способов для сокращения времени проверки работоспособности теста во время его создания, о которых и хочу рассказать. Все примеры взяты из моего опыта, надеюсь, что-то будет полезно.
    Для начала опишу немного архитектуру тестового фреймворка. Инструменты - Visual Studio, C#, CodedUITest, MsTest.

Архитектура тестового фреймворка.

     Допустим, мы тестируем desktop-приложение, требующее определенное время на свою загрузку после запуска, например, 10-15 секунд. Нам невыгодно запускать приложение перед каждым тестом, и закрывать после каждого теста, поэтому мы решаем построить наш фреймворк по такой простой схеме:

  • все классы с тестами наследуются от базового класса RunAppTestFixtureBase
  • у этого класса есть метод, помеченный атрибутом [TestInitialize] (для unit-testing фрейморка Visual Studio, для других фреймворков атрибут может называться по-другому), который проверяет, запущено ли наше приложение, и в случае, если нет, запускает его.
    Таким образом, общую инициализацию тестов мы выносим в базовый класс. Этот метод инициализации может содержать какие-либо дополнительные действия, специфичные для тестирования вашего приложения.
  • В методе [TestCleanup] базового класса мы не указываем, что приложение должно закрываться. По окончании выполнения всех тестов оно закроется автоматически средствами MsTest.
    Отсюда сразу вытекает первый способ сокращения времени выполнения теста при его написании и отладке:

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

2 способ
     В самом простом случае тест у нас состоит из трех логических частей - Setup, Execute и Assert - т.е. какие-то действия по установке начальных значений, непосредственно сами действия, которые мы тестируем, и проверки. 
     Предположим, у вас успешно прошли первые две логические части, а в последней части, части проверок, вы допустили ошибку - например, указали неверные тестовые данные. Вы ее исправляете, и нужно опять проверить, что тест работает хорошо. Поскольку части Setup и Execute уже отлажены, можно просто закомментировать их на время в тесте, привести приложение в то состояние, в котором оно будет после выполнения этих двух частей и запустить тест, в котором фактически выполнится только часть Assert. Это также сэкономит вам время.

3 способ
     У меня не раз случались ситуации, при которых были проблемы с действиями с некоторыми контролами. Например, CodedUI-фреймворк иногда считает контрол заблокированным и выдает исключение, что не может выполнить с ним необходимое действие, например, кликнуть мышкой. Или другая ситуация, когда не может найтись какой-то контрол. Представим, что действие с этим контролом у вас находится в середине или ближе к концу теста, и пока до него дойдет дело, вам нужно пройти кучу форм. Тут можно либо воспользоваться способом 2, либо создать отдельный проект, Sandbox, в котором проводить эксперименты с такими контролами. А потом найденное решение просто перенести в ваш проект.

4 комментария:

  1. По поводу 3-го способа. А почему бы вообще не тестировать контролы отдельно, а проверки функционала делать без них?
    В этом случае мы и UI оттестируем, и функциональность. Но по отдельности - чтобы не мешать всё в кучу, отгребая массу проблем.

    ОтветитьУдалить
    Ответы
    1. Я понимаю, что вы имеете в виду, слушала ваш доклад про пирамиду автоматизации тестирования и не раз сама думала по этому поводу. Мы нашли для себя баланс, когда у нас основные приемочные тест-кейсы выполняются через UI, но в то же время функциональность проверяется через юнит- и интеграционные тесты, которых подавляющее большинство. Например, если взять самый простой пример поиска, через UI мы проверим, что на такой-то форме приложения при вводе в текстовое поле значения поиск будет работать, т.е. результаты правильно отобразятся в таблице (или в другой форме, в которой они выводятся). А сам алгоритм поиска будет проверяться тестами более низкого уровня.

      Удалить
    2. Пирамида - это хорошо. Но я чуть другую мысль хотел сказать, возможно менее глобальную. Раз уж всё равно делаем в 3-м способе отдельный проект с изолированным контролом, то почему бы там же этот контрол и не оттестировать. А в UI-тестах дёргать какой-нибудь внутренний метод кнопки, который будет быстро и надёжно работать.

      http://googletesting.blogspot.com/2013/08/how-google-team-tests-mobile-apps.html - ну или вот тут Hermetic Flow как раз и описывает UI-тесты, которые работают быстро, как как Fake-backend выполняется мгновенно. И такого рода UI-тестов может быть достаточно много, не только для верхушки пирамиды.

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

      Удалить