вторник, июля 20, 2010

Тестирование сервлетов и Task Queue в GAE (с guice ServletModule).

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

Но бывает так что с тестами действительно сильно упрощается и ускоряется процесс разработки даже небольших проектов. Например как раз сейчас делаю проектик на GAE (Google App Engine) который достаточно сложный. Много cron-задач создающих task'и (здесь и далее имеются в виду task'и из Task Queue), которые в свою очередь сами могут порождать task'и. Так как cron и Task Queues на девелоперском сервере поддерживаются довольно-таки условно - возникли неудобства с проверкой работоспособности.

Учитывая что в GAE есть всё для удобного локального тестирования (здесь) было решено позапускать нужные cron-задачи и task'и в нужной последовательности в тесте и там же проверить результат. Очевидно это быстрее чем руками в девелопмент сервере запускать cron-задачи и руками же проверять результат. Более того - так как это тест, то нет нужды потом зачищать datastore чтобы попробовать запустить то же самое, но с другими параметрами. Вобщем экономия времени была ощутимой, не говоря уже о том что куда приятнее откинуться на спинку кресла и смотреть за прогрессом, чем руками рефрешить сервлеты.

Запустить сервлет в тесте не так уж и сложно - я использовал httpunit. Те кто используют обычные сервлеты могут использовать его. У меня же возникла проблема, все мои cron/task-сервлеты были guice'фицированы и поэтому подход с httpunit не годился.

Немного подумав я решил что достаточно будет написать mock's для HttpServletRequest и HttpServletResponse и использовать полученный с помощью guice объект сервлета чтобы всё это заработало. В итоге всё что получилось я выложил сюда: http://code.google.com/p/gaelocaltest/. Там же есть пример использования на главной странице.

Конечно оно сделано весьма быстро на коленке и имеет ряд ограничений, но работает и вполне покрывает типовые задачи. Собственно кода там мало и он примитивен - так что желающие могут взять его за базу для своих целей если вдруг возможностей этого не хватит. Для тех кто не сталкивался с граблями по конфигурации для Local unit testing'а GAE, советую взглянуть на пример конфига.

Вобщем это решение сэкономило мне просто уйму времени. Может быть кому пригодится.

P.S. Для проектов имеющих посещаемость 1.5 человека в сутки и не имеющих постоянно "молотящих" cron/task сервлетов использование guice приведёт к частому появлению паузы при открытии сайта, так как из-за guice увеличится время старта. Сейчас правда все вроде лучше чем год назад - но народ периодически жалуется на эту багофичу GAE. Так что для таких проектов наверное не следует бежать внедрять guice - проще модифицировать мой код под httpunit (самому мне лень).

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

Павел комментирует...

А как вы решаете проблему с удаление данных из базы AEG

Павел комментирует...

при тестирование HttpUnit

Лаврентий Палыч комментирует...

Уточнить бы про проблему, а то не очень понятно о чём речь.

Если имеется в виду то что при использовании LocalServiceTestHelper с LocalDatastoreServiceTestConfig все созданные данные дохнут по завершении каждого теста, то решение наверное такое:

private LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig().setBackingStoreLocation(DS_PATH));

Где DS_PATH путь к datastore. Сам я таким не пользовался, но должно работать по идее.

Ну или тупо создавать все нужные данные в @Before если это возможно конечно (если данных очень много, то надо что-то менять в консерватории).