Изучение Grails: Tестирование приложений Grails

Исходники

Я горячий сторонник принципа разработки программного обеспечения через тестирование (test-driven development – TDD). Нил Форд (Neal Ford, автор книги «The Productive Programmer»), утверждает, что «написание непротестированного кода является примером профессиональной безответственности» (см. раздел Ресурсы). Майкл Физерс (Michael Feathers, автор книги «Working Effectively with Legacy Code»), определяет устаревший код (legacy code) как любой код, для которого не существует тестов. Из этого следует, что написание кода без тестов является старомодной практикой. Лично я не устаю утверждать, что любой проект должен содержать две строки тестового кода на каждую строку кода, который будет отправлен в эксплуатацию.

В статьях серии Изучение Grails пока не затрагивалась тема TDD, поскольку основное внимание уделялось способам использования базовой функциональности Grails. В тестировании кода инфраструктуры (т.е. кода, написанного не вами) также есть определенные преимущества, но на практике мне редко приходится этим заниматься. Я уверен, что Grails корректно сериализует мои объекты POGO в XML, а также сохранит объект Trip в базе данных при вызове trip.save(). В основном необходимость в тестировании возникает при проверке работоспособности вашего собственного кода. При реализации сложного алгоритма необходимо создать один или несколько юнит-тестов, чтобы гарантировать, что алгоритм работает именно так, как от него требуется. В этой статье рассказывается о том, какие средства предоставляет Grails для создания тестового кода для ваших приложений.

Ваш первый тест
Об этой серии

Grails – это инфраструктура разработки Web-приложений, сочетающая использование знакомых Java™-технологий, таких как Spring и Hibernate, с такими современными походами как, например, «соглашения по конфигурации» (convention over configuration). Grails написан на Groovy, обеспечивая бесшовную интеграцию с Java-кодом, добавляя в то же время гибкость и динамизм скриптового языка. Освоив Grails, вы навсегда измените свою точку зрения на разработку Web-приложений.

Рассмотрение вопросов тестирования мы начнем с создания нового класса модели. Этот класс будет реализовывать определенную функциональность, но его нельзя ввести в эксплуатацию без проведения тестов. Выполните команду grails create-domain-class HotelStay, как показано в листинге 1.

Листинг 1. Создание класса HotelStay
$ grails create-domain-class HotelStay

Environment set to development
[copy] Copying 1 file to /src/trip-planner2/grails-app/domain
Created Domain Class for HotelStay
[copy] Copying 1 file to /src/trip-planner2/test/integration
Created Tests for HotelStay

Как видно из листинга 1, в ответ на эту команду Grails создаст пустой класс модели в директории grails-app/domain. Также в директории test/integration будет создан класс GroovyTestCase с пустым методом testSomething() (ниже я объясню разницу между юнит- и интеграционными тестами). Пустой класс HotelStay со сгенерированным тестом показан в листинге 2.

Листинг 2. Пустой класс и автоматически созданный тест
class HotelStay {
}

class HotelStayTests extends GroovyTestCase {
void testSomething() {
}
}

Класс GroovyTestCase представляет собой тонкую Groovy-обертку над юнит-тестами JUnit 3.x. Если вы знакомы с классом TestCase в JUnit, то можно считать, что вы уже знаете, как работает GroovyTestCase. Так или иначе, тестирование заключается в контроле того, что код делает именно то, что он должен делать. Это делается программным образом при помощи различных контролирующих методов, предоставляемых JUnit, в частности assertEquals, assertTrue,assertNull и т.д.
Почему JUnit 3.x, а не 4.x?

Класс GroovyTestCase является наследником TestCase из JUnit 3.x по историческим причинам. Первая версия Groovy, выпущенная в январе 2007 г., поддерживала языковые конструкции Java 1.4. Несмотря на то что приложения могут быть запущены под JVM версий 1.4, 1.5 и 1.6, совместимость на уровне синтаксиса языка осталась на уровне Java 1.4.

Следующим крупным релизом Groovy стала версия 1.5, выпущенная в январе 2008 г. В ней поддерживаются все языковые конструкции 1.5, в том числе generics, статические импорты, циклы for/in, а также аннотации (именно они наиболее важны в контексте JUnit). Тем не менее приложения на основе Groovy 1.5 по-прежнему выполняются в JVM 1.4. Разработчики Groovy обещали, что все версии Groovy 1.x будут обратно совместимы с Java 1.4. Это требование, скорее всего, будет упразднено с выходом Groovy 2.0, который ожидается в конце 2009 или в 2010 г.

Какое же отношение все это имеет к версии классов JUnit, лежащих в основе GroovyTestCase? В JUnit 4.x используются аннотации @test, @before и @after. Эти возможности, несомненно, представляют интерес, но из соображений обратной совместимости с Java 1.4 в качестве основы для GroovyTestCase был по-прежнему выбран JUnit 3.x.

Однако ничто не запрещает вам использовать JUnit 4.x (в разделе Ресурсы приведена ссылка на документацию Groovy по этой теме). Точно также вы можете применять другие инфраструктуры для тестирования, использующие возможности Java 5 (в разделе Ресурсы приведен пример работы с TestNG в Groovy). Groovy совместим с Java на уровне байт-кода, поэтому вы можете использовать те же средства для тестирования в Groovy, что и в Java.

Добавьте содержимое листинга 3 в файлы grails-app/domain/HotelStay.groovy и test/integration/HotelStayTests.groovy.