Примеры конфигураций

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

Ant and Ivy

Ivy зависимости необходимо указывать в ivy.xml файле. Пример довольно простой - для него потребуются лишь JUnit и Hamcrest.

[ivy.xml]

<ivy-module version="2.0">
    <info organisation="org.apache" module="java-build-tools"/>
    <dependencies>
        <dependency org="junit" name="junit" rev="4.11"/>
        <dependency org="org.hamcrest" name="hamcrest-all" rev="1.3"/>
    </dependencies>
</ivy-module>

Теперь очередь за билд скриптом. Его задача - создание jar файла. Билд скрипт сохраняем в build.xml файле.

[build.xml]

<project xmlns:ivy="antlib:org.apache.ivy.ant" name="java-build-tools" default="jar">

    <property name="src.dir" value="src"/>
    <property name="build.dir" value="build"/>
    <property name="classes.dir" value="${build.dir}/classes"/>
    <property name="jar.dir" value="${build.dir}/jar"/>
    <property name="lib.dir" value="lib" />
    <path id="lib.path.id">
        <fileset dir="${lib.dir}" />
    </path>

    <target name="resolve">
        <ivy:retrieve />
    </target>

    <target name="clean">
        <delete dir="${build.dir}"/>
    </target>

    <target name="compile" depends="resolve">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="lib.path.id"/>
    </target>

    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}"/>
    </target>

</project>

Вначале файла мы указали некоторые свойства (properties). Затем мы перечислили задачи одну за другой: разрешение зависимостей (resolve с помощью ivy), очищение (clean), компиляция (compile) и создание jar файла. Это довольно много конфигураций для задачи, которая требуется практически в каждом проекте.

Чтобы запустить задачу по созданию jar файла нужно выполнить команду:

ant jar

Maven

Билд скрипт для maven сохраняется в pom.xml файле. В одном файле хранятся и зависимости, и конфигурации.

[pom.xml]

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0

http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.technologyconversations</groupId>
    <artifactId>java-build-tools</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
        </plugins>
    </build>

</project>

Чтобы запустить команду по созданию jar файла, необходимо выполнить команду:

mvn package

Главное отличие от Ant здесь в том, что нам не надо указывать, что будет запускаться. Мы не создаем задачи, а устанавливаем параметры (зависимости, плагины). Maven использует конвенции и предоставляет задачи "из коробки". Однако и Ant, и Maven xml файлы имеют тенденцию расти со временем. Чтобы проиллюстрировать это возьмем pom.xml с реального проекта по автоматизации.

The major difference is that with Maven we don’t need to specify what should be done. We’re not creating tasks but setting the parameters (what are the dependencies, what plugins to use…). This shows the major difference between Ant and Maven. Later promotes the usage of conventions and provides goals (targets) out-of-the-box. Both Ant and Maven XML files tend to grow big with time. To illustrate that, we’ll add Maven CheckStyle, FindBugs and PMD plugins that will take care of static analysis. All three are fairly standard tools used, in one form or another, in many Java projects. We want all static analysis to be executed as part of a single target verify together with unit tests. Moreover, we should specify the path to the custom checkstyle configuration and make sure that it fails on error. Additional Maven code is following:

[pom.xml]

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>LandsEnd</groupId>
    <artifactId>LandsEnd</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <allure.version>1.3.9</allure.version>
        <aspectj.version>1.7.4</aspectj.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.codeborne</groupId>
            <artifactId>selenide</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>junit</artifactId>
                    <groupId>junit</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>testng</artifactId>
                    <groupId>testng</groupId>
                </exclusion>
            </exclusions>
            <version>2.14</version>
        </dependency>
        <dependency>
            <groupId>ru.yandex.qatools.allure</groupId>
            <artifactId>allure-testng-adaptor</artifactId>
            <version>${allure.version}</version>
        </dependency>
        <dependency>
            <groupId>com.saucelabs</groupId>
            <artifactId>sauce_java_common</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>com.saucelabs</groupId>
            <artifactId>sauce_testng</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.7.3</version>
        </dependency>
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.14</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.16</version>
                <configuration>
                    <testSourceDirectory>${basedir}/src/main/java/</testSourceDirectory>
                    <testClassesDirectory>${project.build.directory}/classes/</testClassesDirectory>
                    <testFailureIgnore>false</testFailureIgnore>
                    <argLine>
                        -javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
                    </argLine>
                    <properties>
                        <property>
                            <name>listener</name>
                            <value>ru.yandex.qatools.allure.testng.AllureTestListener</value>
                        </property>
                    </properties>
                    <argLine>-Dmaven.browser</argLine>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjweaver</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
    <reporting>
        <excludeDefaults>true</excludeDefaults>
        <plugins>
            <plugin>
                <groupId>ru.yandex.qatools.allure</groupId>
                <artifactId>allure-maven-plugin</artifactId>
                <version>LATEST</version>
            </plugin>
        </plugins>
    </reporting>
</project>

Для запуска тестов используем команду:

mvn clean test

И это только небольшой проект по автоматизации. При разработке на реальных проектах приходится писать сотни строк xml даже для выполнения часто используемых основных наборов команд.

Gradle

[build.gradle]

apply plugin: 'java'
apply plugin: 'checkstyle'
apply plugin: 'findbugs'
apply plugin: 'pmd'

version = '1.0'

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
    testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3'
}

Код c Gradle намного короче. Кроме того, вероятно некоторые сочтут его также более понятным нежели XML. Gradle при этом также предоставляет набор доступных задач. Чтобы получить весь список задач, доступных для данной конфигурации выполните следующую команду:

gradle tasks --all

Для изучения и понимания механизмов работы билд инструментов лучше всего подходит Ant, поскольку в нем используется явная конфигурация, из которой легко понять, что из себя представляет та или иная задача, как она реализована.

Однако написание Ant задач довольно быстро становится сложным и утомительным занятием. Maven и Gradle предоставляют большое количество готовых к использованию задач с помощью плагинов.

К примеру следующая команда Gradle открывает доступ к 20+ задач, готовых к использованию:

[build.gradle]

apply plugin: 'java'

Задача 1. Напишите простую Maven конфигурацию для запуска тестов в Maven, используйте maven surefire plugin.

Задача 2. Сделайте то же самое с Ant и Gradle.

Last updated