Перейти к тексту

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

Профиль создается, когда вы в первый раз заходите в developerWorks. Выберите данные в своем профиле (имя, страна/регион, компания) которые будут общедоступными и будут отображаться, когда вы публикуете какую-либо информацию. Вы можете изменить данные вашего ИБМ аккаунта в любое время.

Вся введенная информация защищена.

  • Закрыть [x]

При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

Вся введенная информация защищена.

  • Закрыть [x]

Практически Groovy : Ускорение модульного тестирования кода Java с помощью Groovy

Эндрю Гловер, президент компании, Stelligent Incorporated
Эндрю Гловер является президентом компании Stelligent Incorporated , которая помогает другим фирмам решать проблемы качества программного обеспечения. Для этого используются эффективные стратегии тестирования и технологии непрерывной интеграции, которые позволяют коллективам разработчиков постоянно контролировать качество кода, начиная с ранних стадий разработки. Просмотрите блог Энди , там можно найти список его публикаций.

Описание:  Не так давно автор developerWorks Эндрю Гловер написал в рамках серии alt.lang.jre статью, знакомящую читателей с Groovy, новым предложенным в качестве стандартного языком для платформы Java. Реакция читателей была фантастической, поэтому мы решили запустить эту колонку, чтобы предоставить пользователям практическое руководство по работе с этой новой технологией. Этот первый выпуск знакомит с простой стратегией модульного тестирования кода Java с помощью Groovy и JUnit.

Больше статей из этой серии

Дата:  25.12.2007
Уровень сложности:  простой
Активность:  6570 просмотров
Комментарии:  


Я хочу начать с признания: я маньяк модульного тестирования. Мне постоянно хочется писать модульные тесты еще и еще. Если я длительное время веду разработку без написания соответствующих модульных тестов, я начинаю нервничать. Модульное тестирование даёт мне уверенность в том, что мой код работает, и я могу изменить его в любой момент, не опасаясь, что он сломается.

Кроме того, как настоящий маньяк, я обычно пишу множество тестовых примеров. Однако самое большое удовольствие я получаю не в процессе написания тестов, а когда вижу их результаты. Следовательно, если я могу быстрее писать тесты, я смогу быстрее видеть результаты. Тогда я буду чувствовать себя еще лучше. Еще быстрее.

Чтобы ублажить свою манию, недавно я начал изучать Groovy, и пока он мне очень нравится. Этот новый язык придает модульному тестированию исключительную скорость и заслуживает весьма серьёзного исследования. В этой статье, первой в новой серии, посвященной практическим вопросам применения Groovy, я познакомлю вас с прелестями модульного тестирования в Groovy. Я начну с обзора уникального вклада Groovy в разработку на платформе Java, а затем перейду к обсуждению особенностей модульного тестирования с помощью Groovy и JUnit, делая особый акцент на расширении класса TestCase JUnit в Groovy. Я закончу повествование рабочим примером, который покажет, как интегрировать эти замечательные функции с Eclipse и Maven.

Нет пуризму Java!

Прежде чем приступать к практическим аспектам модульного тестирования в Groovy, я думаю, важно поговорить о более общем вопросе его применения в разработке. В действительности Groovy - это не единственный язык сценариев, который работает в среде исполнения Java (JRE), - но это единственный язык, который был предложен в качестве стандартного для платформы Java. Как некоторые из вас уже знают из серии alt.lang.jre (см. раздел Ресурсы), существует множество вариантов языков сценариев для платформы Java, большинство из которых предоставляет весьма гибкие среды для быстрой разработки приложений.

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

Хотя я надеюсь, что мне удастся убедить вас в рамках этой серии в том, что язык Java не является и не должен являться единственным средством разработки приложений, но применение языков сценариев может быть оправдано в одних случаях и не оправдано в других. Профессионала отличает от дилетанта знание того, когда следует применять возможности языков сценариев и когда воздержаться от этого.

Об этой серии руководств

Чтобы применять какой-либо инструмент в практике разработки, необходимо знать, как им пользоваться и когда его лучше отложить в сторону. Языки сценариев могут быть чрезвычайно полезным помощником, но только если применять их правильно и в подходящих ситуациях. В связи с этим в серии статей Практически Groovy мы рассматриваем практические применения Groovy и показываем, когда и как его можно успешно использовать.

Например, языки сценариев обычно не очень хорошо подходят для высокоскоростных корпоративных приложений, обрабатывающих большое число транзакций; для этих случаев лучше всего может подойти обычный J2EE. С другой стороны, языки сценариев - и, в частности, Groovy - могут иметь смысл в случаях, когда необходимо быстрое создание прототипов небольших, крайне специализированных приложений, от которых не требуется высокой производительности, таких, например, как системы настройки или сборки. Они также почти идеально подходят для приложений формирования отчетов и, что более важно, для модульного тестирования.

Почему Groovy подходит для модульного тестирования?

Прозрачная интеграция с платформой Java делает Groovy особенно привлекательным по сравнению с другими языками сценариев. Поскольку Groovy основан на языке Java (в отличие от других языков для JRE, которые обычно основываются на более ранних предшественниках), он чрезвычайно прост в изучении для разработчика Java. И после того, как этап обучения будет пройден, Groovy может стать не имеющей равных платформой быстрой разработки.

Секрет успеха Groovy в этом плане кроется в его синтаксисе, который является синтаксисом Java, но со значительно меньшим количеством правил. Например, в Groovy не обязательны точки с запятой, также не обязательны типы переменных и модификаторы доступа. Кроме того, Groovy использует знакомые вам стандартные библиотеки Java, в том числе Collections и File/IO. .И, наконец, в Groovy вы можете использовать любые библиотеки Java, в том числе и JUnit.

Очевидно, что Java-подобный синтаксис Groovy с менее строгими правилами, возможность использования стандартных библиотек Java и короткий цикл разработки делают его идеальным кандидатом для быстрой разработки модульных тестов. Однако я не требую верить мне на слово; давайте посмотрим, как это выглядит в программном коде.


JUnit и Groovy

Модульное тестирование кода Java в Groovy проводится очень просто, и начать знакомство с ним можно по-разному. Наиболее очевидный выбор - это использование промышленного стандарта - JUnit. JUnit обладает непревзойдённой простотой и широчайшими возможностями, не имеет равных по распространённости как полезного инструмента разработки Java, и ничто не мешает нам сочетать JUnit и Groovy - так зачем изобретать колесо? На самом деле я готов поспорить, что, увидев тандем JUnit и Groovy в действии, вы уже не откажетесь от него! Здесь важно помнить, что в JUnit и Groovy можно сделать все то же, что и в языке Java - хотя и со значительно меньшими затратами сил.

Первое знакомство

Загрузив JUnit и Groovy (см. раздел Ресурсы), вы можете действовать одним из двух способов. Первый вариант состоит в написании обычных тестовых примеров JUnit так же, как и раньше, расширяя отличный класс JUnit TestCase. Второй вариант заключается в использовании интересного расширения Groovy GroovyTestCase, которое, в свою очередь, будет расширять класс JUnit TestCase. Первый вариант - максимально Java-подобный путь к успеху. С другой стороны, второй вариант максимально погружает вас в мир Groovy.

Для начала представьте объект Java, который применяет фильтр к заданной строке ( string) и возвращает булево значение(boolean), обозначающее соответствие строки фильтру. Этот фильтр может быть простой string операцией, например indexOf(), или, что дает больше возможностей, регулярным выражением. Нужный фильтр задается в ходе работы посредством метода setFilter(), а методу apply() передается фильтруемая string. В листинге 1 показан пример такого интерфейса Filter на чистом коде Java:


Листинг 1. Простой интерфейс Java-фильтра
public interface Filter {
  void setFilter(String fltr);  
  boolean applyFilter(String value);
}

Смысл этой функции состоит в отборе подходящих или неподходящих названий пакетов из большого списка. Соответственно я создал две реализации:RegexPackageFilter и SimplePackageFilter.

Сочетание возможностей и простоты Groovy и JUnit позволяет создать элегантный тест, приведенный в листинге 2:


Листинг 2. RegexFilterTest в Groovy, использующий JUnit
import junit.framework.TestCase
import com.vanward.sedona.frmwrk.filter.impl.RegexPackageFilter

class RegexFilterTest extends TestCase {  

  void testSimpleRegex() {
    fltr = new RegexPackageFilter()
    fltr.setFilter("java.*")
    val = fltr.applyFilter("java.lang.String")		
    assertEquals("value should be true", true, val)		
  }
}

Код листинга 2 должен показаться вам знакомым, независимо от того, знакомы вы с Groovy или нет, поскольку это обычный код Java без точек с запятой, модификаторов доступа и типов переменных! В приведенном выше тесте JUnit содержится один тестовый пример, testSimpleRegex(), который пытается проверить правильность нахождения RegexPackageFilter соответствия "java.lang.String", используя регулярное выражение "java.*".


Groovy расширяет JUnit

Расширение класса TestCase JUnit с для увеличения его возможностей является общепринятой методикой, используемой практически в каждом расширении JUnit. Среда DbUnit (см. раздел Ресурсы), например, предлагает удобный DatabaseTestCase, который невероятно облегчает управление состояниями базы данных, а незаменимый MockStrutsTestCase (из среды StrutsTestCase; см. раздел Ресурсы) предлагает виртуальный контейнер servlet для исполнения кода struts. Обе этих мощные среды элегантно расширяют JUnit, предоставляя функции, которых нет в его основном коде; теперь то же самое сделано и в Groovy!

Как и в StrutsTestCase и DbUnit, расширение класса TestCase JUnit в Groovy привносит новые важные функции в инструментарий разработчика. Это расширение позволяет вам запускать тесты с помощью команды groovy, а также предлагает множество новых методов assert. Эти методы могут быть полезны при определении правильности работы сценариев, проверке длины и содержимого массивов различных типов, а также во многих других случаях.


Играем с GroovyTestCase

Лучший способ понять, чем может быть полезен GroovyTestCase - посмотреть на него в действии. В листинге 3 я написал новый SimpleFilterTest, но на этот раз для этого я расширил GroovyTestCase:


Листинг 3. Настоящий GroovyTestCase
import groovy.util.GroovyTestCase
import com.vanward.sedona.frmwrk.filter.impl.SimplePackageFilter

class SimpleFilterTest extends GroovyTestCase {
	
  void testSimpleJavaPackage() {
    fltr = new SimplePackageFilter()
    fltr.setFilter("java.")		
    val = fltr.applyFilter("java.lang.String")		
    assertEquals("value should be true", true, val)
  }	
}

Обратите внимание, что этот тест может быть запущен из командной строки без метода main(), который необходим для запуска тестов JUnit на базе Java. На самом деле, если бы я написал приведенный вышеSimpleFilterTest в коде Java, он напоминал бы код, приведенный в листинге 4:


Листинг 4. Тот же тестовый пример в коде Java
import junit.framework.TestCase;
import com.vanward.sedona.frmwrk.filter.Filter;
import com.vanward.sedona.frmwrk.filter.impl.SimplePackageFilter;

public class SimplePackageFilterTest extends TestCase {       

   public void testSimpleRegex() {
	Filter fltr = new SimplePackageFilter();
	fltr.setFilter("java.");
	boolean val = fltr.applyFilter("java.lang.String");
	assertEquals("value should be true", true, val);
   }
	
   public static void main(String[] args) {
 	junit.textui.TestRunner.run(SimplePackageFilterTest.class);
   }
}

Тестирование с контролем

В дополнение к возможности запуска тестов из командной строки GroovyTestCase предоставляет вам, в частности, очень полезные методы assert. assertArrayEquals, например, контролирует равенство двух массивов, проверяя отдельные значения и соответствующие длины. Операторы контроля Groovy в действии можно видеть начиная с примера, приведенного в листинге 5 – изящного метода, построенного на базе Java, который разделяет string на массивы. (Обратите внимание, что для написания приведенного ниже примера класса я мог бы использовать функции string, введенные в Java 1.4. Для обеспечения обратной совместимости с Java 1.3 я использовал класс Jakarta Commons StringUtils.)


Листинг 5. Определение класса Java StringSplitter
import org.apache.commons.lang.StringUtils;

public class StringSplitter {
  public static String[] split(final String input, final String separator){
   return StringUtils.split(input, separator);
  }
}

В листинге 6 показано, как просто протестировать этот класс с помощью теста Groovy и соответствующего метода assertArrayEquals:


Листинг 6. Использование assertArrayEquals в GroovyTestCase
import groovy.util.GroovyTestCase
import com.vanward.resource.string.StringSplitter

class StringSplitTest extends GroovyTestCase {
	
  void testFullSplit() {
    splitAr = StringSplitter.split("groovy.util.GroovyTestCase", ".")		
    expect = ["groovy", "util", "GroovyTestCase"].toArray()
    assertArrayEquals(expect, splitAr)		
  }	
}


Другие возможности

Groovy позволяет запускать тесты поодиночке или пакетами. Запуск одного теста благодаря GroovyTestCase не требует никаких усилий. Просто введите команду groovy, после которой укажите интересующий вас тест - и всё готово, как видно в листинге 7:


Листинг 7. Запуск GroovyTestCase с помощью команд groovy
$./groovy test/com/vanward/sedona/frmwrk/filter/impl/SimpleFilterTest.groovy
.
Time: 0.047

OK (1 test)

Groovy также предлагает стандартный тестовый пакет JUnit, который называется GroovyTestSuite. Просто запустите этот тест и передайте ему путь к вашему сценарию. Этот тест исполнит ваш сценарий аналогично команде groovy. У этой методики есть отличное свойство - она позволяет запускать сценарии в интегрированных средах разработки. Например, в Eclipse я могу просто создать новую конфигурацию для нашего примера проекта (не забыв отметить параметр "Включать внешние jar в поиск основного класса" ("Include external jars when searching for a main class")), после чего найти основной класс groovy.util.GroovyTestSuite, как показано на рисунке 1:


Рисунок 1. Использование Eclipse для запуска GroovyTestSuite
Рисунок 1. Использование Eclipse для запуска GroovyTestSuite

На рисунке 2 вы можете видеть, что произойдёт, если я перейду на вкладку Arguments и укажу путь к моему сценарию:


Рисунок 2. Указание пути к сценарию в Eclipse
Рисунок 2. Указание пути к сценарию в Eclipse

Запуск любимого сценария JUnit в Groovy так же прост, как поиск соответствующего файла конфигурации запуска в Eclipse.


Тестирование с помощью Ant и Maven

Прелесть сред, подобных JUnit, состоит в том, что вы можете запускать целый комплект тестов в ходе сборки без вмешательства оператора. Чем больше людей добавляют тестовые примеры в базу кода, тем больше расширяется общий тестовый комплект, который становится отличной платформой для регрессионного тестирования. Кроме того, среды сборки, такие как Ant и Maven, имеют дополнительные функции формирования отчетов, которые подводят итоги запуска пакетов JUnit.

Наиболее простой путь состоит в том, чтобы включить в сборку множества тестовых примеров Groovy, откомпилировать их в обычный байт-код Java и включить в стандартные пакетные команды JUnit, реализованные в Ant и Maven. К счастью, в Groovy реализован тег Ant, который включает в себя компиляцию сценариев Groovy в байт-код, поэтому процесс преобразования сценариев в функциональный код становится предельно простым. Например, если вы используете для сборки Maven, достаточно просто добавить две новые цели в файл maven.xml, две новые зависимости в файл project.xml, один простой флаг в файл build.properties - и всё.

Я начну с изменения файла maven.xml, указав новую цель для компиляции примера сценария, как показано в листинге 8:


Листинг 8. Пример файла maven.xml, определяющего цель Groovyc
 <goal name="run-groovyc" prereqs="java:compile,test:compile">
   
   <path id="groovy.classpath">
     <pathelement path="${maven.build.dest}"/>
     <pathelement path="target/classes"/>
     <pathelement path="target/test-classes"/>
     <path refid="maven.dependency.classpath"/>
   </path>

 <taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc">
    <classpath refid="groovy.classpath"/>
 </taskdef>

 <groovyc destdir="${basedir}/target/test-classes" srcdir="${basedir}/test/groovy" 
          listfiles="true">
	<classpath refid="groovy.classpath"/>
 </groovyc>

 </goal>

В приведенном выше коде производится несколько действий. Во-первых, я определяю новую цель run-groovyc. У этой цели есть два предварительных условия - java:compile, которое компилирует наш пример исходного кода, и test:compile, которое компилирует все нормальные классы Java-JUnit. После этого я создаю путь класса с помощью тега <path>. В нашем этом случае в путь класса входит директория сборки (где хранится скомпилированный исходный код) и все соответствующие зависимости (т.е. файлы JAR). После этого я определяю задачу groovyc с помощью тега Ant <taskdef>.

Обратите внимание, как я сообщаю Maven о том, где искать класс org.codehaus.groovy.ant.Groovyc в пути класса. В последних строках примера я определил тег <groovyc>, который компилирует все сценарии Groovy, обнаруженные в директории test/groovy, и размещает полученные файлы .class в папке target/test-classes.

Важные подробности

Чтобы скомпилировать сценарии Groovy и запустить получившийся код, мне нужно определить две новые зависимости (groovy и asm) в файле project.xml, как показано в листинге 9:


Листинг 9. Новые зависимости для файла project.xml
  <dependency>
    <groupId>groovy</groupId>
    <id>groovy</id>
    <version>1.0-beta-6</version>
  </dependency>

  <dependency>
    <groupId>asm</groupId>
    <id>asm</id>
    <version>1.4.1</version>
  </dependency>

После компиляции сценариев в обычный байт-код Java их можно запустить любой стандартной программой запуска JUnit. Поскольку в Ant и Maven есть тег запуска, следующий шаг будет состоять в передаче JUnit только что скомпилированных сценариев Groovy. А поскольку программа запуска JUnit в Maven производит поиск тестов, которые необходимо запустить, по шаблону, мне нужно добавить специальный флаг в файл build.properties, как показано в листинге 10, который говорит Maven, что надо искать классы, а не файлов .java:


Листинг 10. Файл build.properties проекта Maven
 maven.test.search.classdir = true

И, наконец, я определяю тест goal в файле maven.xml, показанном в листинге 11. Это гарантирует, что сценарии Groovy будут скомпилированы с новой целью run-groovyc перед запуском модульных тестов.


Листинг 11. Новая цель для maven.xml
  <goal name="test">
    <attainGoal name="run-groovyc"/>
    <attainGoal name="test:test"/>    	
  </goal>

Последнее, но не менее важное...

Определив две новые цели (одна для компиляции сценариев и одна для запуска совместных тестов JUnit Java и Groovy), остаётся только запустить их и убедиться, что всё работает!

В листинге 12 вы можете увидеть, что произойдёт, когда я запущу Maven и передам ему цель test, которая сначала достигнет цели run-groovyc (при этом также будут достигнуты цели java:compile и test:compile), после чего достигнет стандартной встроенной цели Maven test:test. Обратите внимание, как цель test:test принимает только что созданные сценарии Groovy - или, в нашем случае, только что скомпилированные сценарии Groovy - и обычный тест JUnit Java.


Листинг 12. Запуск новой цели
$ ./maven test

test:
java:compile:
    [echo] Compiling to /home/aglover/dev/target/classes
    [javac] Compiling 15 source files to /home/aglover/dev/target/classes

test:compile:
    [javac] Compiling 4 source files to /home/aglover/dev/target/test-classes

run-groovyc:
    [groovyc] Compiling 2 source files to /home/aglover/dev/target/test-classes
    [groovyc] /home/aglover/dev/test/groovy/test/RegexFilterTest.groovy
    [groovyc] /home/aglover/dev/test/groovy/test/SimpleFilterTest.groovy

test:test:    
    [junit] Running test.RegexFilterTest
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.656 sec    
    [junit] Running test.SimpleFilterTest
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.609 sec
    [junit] Running test.SimplePackageFilterTest
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.578 sec    
BUILD SUCCESSFUL
Total time: 42 seconds
Finished at: Tue Sep 21 17:37:08 EDT 2004


Повторение сегодняшнего урока

Из этого первого выпуска Практически Groovy вы узнали об одном из наиболее практичных применений этого превосходного нового языка сценариев. Всё большее число разработчиков считают модульное тестирование важной частью процесса разработки; а Groovy и JUnit предельно упрощают модульное тестирование кода Java.

Простой синтаксис Groovy и его гибкость делают его превосходной платформой для быстрого написания эффективных тестов JUnit и их включения в автоматические сборки. Маньяка качества кода вроде меня такое сочетание в значительной степени избавляет от нервотрепки и позволяет мне заниматься тем, что я люблю: писать пуленепробиваемые программы. Быстрее.

Поскольку это новая серия, мы очень просим вас помочь нам определить направление её развития. Если вы хотите что-то узнать о Groovy, черкните мне пару строчек об этом! Тем временем я надеюсь, что вы дождетесь следующего выпуска, в котором я расскажу о написании сценариев Ant в Groovy.


Ресурсы

Об авторе

Эндрю Гловер является президентом компании Stelligent Incorporated , которая помогает другим фирмам решать проблемы качества программного обеспечения. Для этого используются эффективные стратегии тестирования и технологии непрерывной интеграции, которые позволяют коллективам разработчиков постоянно контролировать качество кода, начиная с ранних стадий разработки. Просмотрите блог Энди , там можно найти список его публикаций.

Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Спасибо. Эта запись была помечена для модератора.


Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Сообщение о нарушении не было отправлено. Попробуйте, пожалуйста, позже.


developerWorks: вход


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


При первом входе в developerWorks для Вас будет создан профиль. Выберите информацию отображаемую в Вашем профиле — скрыть или отобразить поля можно в любой момент.

Выберите ваше отображаемое имя

При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

(Должно содержать от 3 до 31 символа.)


Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Оценить эту статью

Комментарии

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java
ArticleID=279201
ArticleTitle=Практически Groovy : Ускорение модульного тестирования кода Java с помощью Groovy
publish-date=12252007
author1-email=aglover@stelligent.com
author1-email-cc=