Когда перед вашей командой стоит задача написать действительно крупный проект, всегда становится задача тестировать написанный код. Если сервер тестировать относительно легко, то JS код чаще всего тестировать просто невозможно в связи с его природой.
Природу JS решила обойти отличная команда разработчиков, которая создала уникальный в своем роде продукт, который позволяет написать приемочные тесты, которые будут взаимодействовать на прямую с браузером. У них получилось очень и очень круто, но грабли были, есть и будут. По этому я расскажу о граблях, которые обычно встречаю во время работы с данным прекрасным продуктом.
А поговорим о следующем:
Данная статья больше ориентирована на новичков, чем на профессионалов.
Часто встает вопрос, как спроектировать тесты, чтоб сократить написание кода и не заниматься копипастом. Обычно используются generic файлы, которые наследуют unitTest класс вашего языка. У нас всегда есть возможность изменить поведение для какой-то группы тестов, не затрагивая другие группы. К примеру:
Когда вы отделяете функционал по категориям, выносите его в директории, а в каждой директории создавайте свой generic. Каждый тест должен наследовать класс generic с которым он лежит в директории. Generic может быть даже пустым, в будущем он пригодится, даю гарантию.
Разница между юнит тестами и приемочными тестами заключается, что в unittest обычно тестируют алгоритмы и логику, а приемочные уже тестируют саму систему, с реальными данными, которые получают из работающей БД.
Задача всех тестов, быть изолированными друг от друга. А значит на каждый запуск теста, нужно создавать новую тестовую БД. У каждого unittest функционала языка есть метод setUp, который вызывается перед запуском теста. Попробуйте в нем изменить настройки до иницилизации базы данных. Так вы сможете полностью изолироваться от других тестов и существующих данных, а если вы еще используете механизмы кэширования, очистите кэш или воспользуйтесь пустым хранилищем кэша как и с БД.
По сути, это данные которые будут записаны в вашу тестовую БД, для того чтоб браузер открыл сайт и не получил ошибок. Базовые данные стоит записать в setUp методе главного generic`a. А остальные записывать по мере потребностей данных в самих тестах.
Создайте путь для возможного дебага, часто бывает так, что тесты по не понятной причине глохнут с ошибкой, часто бывает что нужно сохранить базу и оставить браузер в живых. Возможно вам и sleep подойдет? Если вы сделали функционал сохранения базы, сделайте так-же функционал очистки старых баз. У меня к примеру mongoDB смог за неделю разработки создать 80гб баз данных.
Когда открывается браузер, запомните, он никак не связан с вашим тестом. Если селениум просто откроет браузер и начнет выполнять операции, скорее всего он будет выполнять их над существующим проектом. Передайте в браузер параметры, которые помогут идентифицировать нужную тестовую базу. В свое время, браузер должен будет передать информацию на сервер.
Вот тут вам нужно будет сесть и подумать, как сделать для самого себя жизнь прекрасней.
К примеру, у вас асинхронное многопользовательское real time приложение(игра), нужно писать тесты где могут взаимодействовать два и более пользователей. Посмотрите, будет ли вам удобно переключатся между окнами браузера с помощью драйвера? Нет, напишите свою простую реализацию.
Нужно собственные assert`ы? К примеру проверить существование элемента в дереве?
Вполне вероятно, что у вашего проекта есть свои особенности и нужно подготовить некоторую функциоальную часть тестов для этого.
Всегда при тестировании, нам нужно будет выполнять таймауты. Толи это будет загрузка страницы, ajax или socket запрос на сервер. С загрузкой страницы драйвера содержат встроенный метод для ожидания. Но вот с ajax и socket запросами всё сложнее. Вам нужно будет написать счетчик отправленных запросов и полученных ответов. Когда вы отправляем запрос, счетчик инкрементится, когда приходит ответ, декрементится. В самом generic`e реализовываем метод, который будет проверять данный счетчик и если он не равен 0, то пусть ждет, но ограничивайте ожидание, ответ от сервера может и не прийти.
Порой нам нужно будет получать состояния или какие-то данные, для проверки их значений с ожидаемыми. Сразу напишите пути получения этих данных. К примеру если вы используете AngularJS, то чтоб получить доступ к данным сервиса, напишите прослойку для этого.
Если нету какой-то возможности с помощью тестов эмулировать действия пользователя, то нужно вызывать обработчики этих событий. Дайте возможность тестам стучаться к исполняемому JS коду.
Чаще всего получается так, что тест работает у вас на компе, но не работает у других. Это может быть связано с ОС, версией селениума, разрешением монитора и вплоть до версий браузера. Советую, заведите себе дешевый VPS, на котором вы сможете запускать тесты. На серверной линухе можно запускать тесты прямо из браузера. К примеру ман, который мне помог www.alittlemadness.com/2008/03/05/running-selenium-headless В добавок, вы сэкономите свое время, пока будете ожидать завершения тестов. Не забудьте, браузер весьма требовательный по оперативке, добавьте хороший запас swap.
Первое, посетите code.google.com/p/selenium/issues/list и пробегитесь глазами по багам.
Второе, если вы уверены, что это обязано работать, пройдитесь JS дебагом по коду. Вполне вероятно что вы найдете место, которое бажит по вине самого селениума или драйвера. К примеру я наткнулся на баг, когда при mouse move, chomedriver не передает событие which, которе отвечает за текущую нажатую кнопку мыши.
Так-же известная неприятность, которая связа со скролами. Селениум ничего не умеет скролить кроме скролла у body. Решения два. Писать функцию скролла или на сервере ставить большое разрешение виртуального монитора.
Часто тесты могут глючить из-за таймаутов. Воспользуйтесь функционалом, который сможет повторят тесты. Дайте ему возможность на сервере перезапускать тест раза 3. Если тест валится, значит он не рабочий, если он валится периодически, проблемы в таймаутах, которые не заметны пользователю, но заметны самому селениуму.
Тестируйте и всегда покрывайте тестами исправленные баги. Не важно на сколько долго будут исполняться тесты, главное чтоб ваше детище работало всегда стабильно.
Природу JS решила обойти отличная команда разработчиков, которая создала уникальный в своем роде продукт, который позволяет написать приемочные тесты, которые будут взаимодействовать на прямую с браузером. У них получилось очень и очень круто, но грабли были, есть и будут. По этому я расскажу о граблях, которые обычно встречаю во время работы с данным прекрасным продуктом.
А поговорим о следующем:
- Архитектура тестов
- Запуск тестов
- Кодовая база
- Таймауты
- Взаимодействие кода тестов и браузера.
- Разные среды исполнения
- Баги драйверов и самого селениума
Данная статья больше ориентирована на новичков, чем на профессионалов.
Архитектура тестов
Часто встает вопрос, как спроектировать тесты, чтоб сократить написание кода и не заниматься копипастом. Обычно используются generic файлы, которые наследуют unitTest класс вашего языка. У нас всегда есть возможность изменить поведение для какой-то группы тестов, не затрагивая другие группы. К примеру:
unittest.py
seleniun/
- generic.py
menu/
- generic.py
- menuActionTest.py
- menuDisableTest.py
articles/
- generic.py
- articlesLoadTest.py
- articlesActionsTest.py
Когда вы отделяете функционал по категориям, выносите его в директории, а в каждой директории создавайте свой generic. Каждый тест должен наследовать класс generic с которым он лежит в директории. Generic может быть даже пустым, в будущем он пригодится, даю гарантию.
Запуск тестов
Разница между юнит тестами и приемочными тестами заключается, что в unittest обычно тестируют алгоритмы и логику, а приемочные уже тестируют саму систему, с реальными данными, которые получают из работающей БД.
База данных
Задача всех тестов, быть изолированными друг от друга. А значит на каждый запуск теста, нужно создавать новую тестовую БД. У каждого unittest функционала языка есть метод setUp, который вызывается перед запуском теста. Попробуйте в нем изменить настройки до иницилизации базы данных. Так вы сможете полностью изолироваться от других тестов и существующих данных, а если вы еще используете механизмы кэширования, очистите кэш или воспользуйтесь пустым хранилищем кэша как и с БД.
Фикстуры
По сути, это данные которые будут записаны в вашу тестовую БД, для того чтоб браузер открыл сайт и не получил ошибок. Базовые данные стоит записать в setUp методе главного generic`a. А остальные записывать по мере потребностей данных в самих тестах.
Сохранение данных базы
Создайте путь для возможного дебага, часто бывает так, что тесты по не понятной причине глохнут с ошибкой, часто бывает что нужно сохранить базу и оставить браузер в живых. Возможно вам и sleep подойдет? Если вы сделали функционал сохранения базы, сделайте так-же функционал очистки старых баз. У меня к примеру mongoDB смог за неделю разработки создать 80гб баз данных.
Передача подключения
Когда открывается браузер, запомните, он никак не связан с вашим тестом. Если селениум просто откроет браузер и начнет выполнять операции, скорее всего он будет выполнять их над существующим проектом. Передайте в браузер параметры, которые помогут идентифицировать нужную тестовую базу. В свое время, браузер должен будет передать информацию на сервер.
Кодовая база
Вот тут вам нужно будет сесть и подумать, как сделать для самого себя жизнь прекрасней.
К примеру, у вас асинхронное многопользовательское real time приложение(игра), нужно писать тесты где могут взаимодействовать два и более пользователей. Посмотрите, будет ли вам удобно переключатся между окнами браузера с помощью драйвера? Нет, напишите свою простую реализацию.
Нужно собственные assert`ы? К примеру проверить существование элемента в дереве?
Вполне вероятно, что у вашего проекта есть свои особенности и нужно подготовить некоторую функциоальную часть тестов для этого.
Таймауты
Всегда при тестировании, нам нужно будет выполнять таймауты. Толи это будет загрузка страницы, ajax или socket запрос на сервер. С загрузкой страницы драйвера содержат встроенный метод для ожидания. Но вот с ajax и socket запросами всё сложнее. Вам нужно будет написать счетчик отправленных запросов и полученных ответов. Когда вы отправляем запрос, счетчик инкрементится, когда приходит ответ, декрементится. В самом generic`e реализовываем метод, который будет проверять данный счетчик и если он не равен 0, то пусть ждет, но ограничивайте ожидание, ответ от сервера может и не прийти.
Взаимодействие кода тестов и браузера.
Порой нам нужно будет получать состояния или какие-то данные, для проверки их значений с ожидаемыми. Сразу напишите пути получения этих данных. К примеру если вы используете AngularJS, то чтоб получить доступ к данным сервиса, напишите прослойку для этого.
Если нету какой-то возможности с помощью тестов эмулировать действия пользователя, то нужно вызывать обработчики этих событий. Дайте возможность тестам стучаться к исполняемому JS коду.
Разные среды исполнения
Чаще всего получается так, что тест работает у вас на компе, но не работает у других. Это может быть связано с ОС, версией селениума, разрешением монитора и вплоть до версий браузера. Советую, заведите себе дешевый VPS, на котором вы сможете запускать тесты. На серверной линухе можно запускать тесты прямо из браузера. К примеру ман, который мне помог www.alittlemadness.com/2008/03/05/running-selenium-headless В добавок, вы сэкономите свое время, пока будете ожидать завершения тестов. Не забудьте, браузер весьма требовательный по оперативке, добавьте хороший запас swap.
Баги драйверов и самого селениума
Первое, посетите code.google.com/p/selenium/issues/list и пробегитесь глазами по багам.
Второе, если вы уверены, что это обязано работать, пройдитесь JS дебагом по коду. Вполне вероятно что вы найдете место, которое бажит по вине самого селениума или драйвера. К примеру я наткнулся на баг, когда при mouse move, chomedriver не передает событие which, которе отвечает за текущую нажатую кнопку мыши.
Так-же известная неприятность, которая связа со скролами. Селениум ничего не умеет скролить кроме скролла у body. Решения два. Писать функцию скролла или на сервере ставить большое разрешение виртуального монитора.
Часто тесты могут глючить из-за таймаутов. Воспользуйтесь функционалом, который сможет повторят тесты. Дайте ему возможность на сервере перезапускать тест раза 3. Если тест валится, значит он не рабочий, если он валится периодически, проблемы в таймаутах, которые не заметны пользователю, но заметны самому селениуму.
На последок
Тестируйте и всегда покрывайте тестами исправленные баги. Не важно на сколько долго будут исполняться тесты, главное чтоб ваше детище работало всегда стабильно.