Повторяйте за мной: Муравей не является языком программирования .Фактически, запишите это 100 раз на доске.
Ant не является языком программирования, поэтому не думайте об этом как таковом.Это матрица зависимостей сборки.
Программистам сложно обдумать эту идею.Они хотят сообщить муравью каждый шаг и когда это должно быть сделано.Они хотят петли, если заявления.Они прибегнут к использованию скрипта build.sh
для вызова различных целей в Ant, потому что вы не можете легко запрограммировать Ant.
В Ant вы указываете отдельные задачи, и какие задачи зависят от других задач, и позволяетеAnt обрабатывает, где и когда выполняются вещи.
Я говорю о том, что обычно вы не разбиваете задачи на подзадачи, а затем пытаетесь вызвать на них <ant>
или <subant>
.
Имейте отдельные задачи, но затем дайте каждой задаче знать, от каких других задач они зависят.Также помните, что в Ant нет истинного порядка.Когда вы перечисляете задачи depends=
, нет никакой гарантии, в каком порядке они будут выполняться.
Стандартный стиль муравья (что означает способ, которым я это делаю (иначе Правильный путь), ине то, как мой коллега делает это (он же «Неправильный путь»)), обычно говорится, что задачи определяются в верхней части файла свойств, а не в какой-либо цели.Вот основная схема того, как я структурирую build.xml
:
<project name=...>
<!-- Build Properties File -->
<property name="build.properties.file"
value="${basedir}/build.properties"/>
<property file="${build.properties.file"/>
<!-- Base Java Properties -->
<property name="..." value="..."/>
<taskdef/>
<taskdef/>
<!-- Javac properties -->
<property name="javac..." value="..."/>
<task/>
<task/>
</project>
Это создает интересную иерархию.Если у вас есть файл с именем build.properties
, он переопределит свойства, определенные в сценарии build.xml
.Например, у вас есть:
<property name="copy.verbose" value="false"/>
<copy todir="${target}"
verbose="${copy.verbose}">
<fileset dir="${source}"/>
</copy>
Вы можете включить подробную копию, просто установив copy.verbose = true
в своем файле build.properties
.И вы можете указать другой файл свойств сборки, просто указав это в командной строке:
$ ant -Dbuild.properties.file="my.build.properties"
(Да, да, я знаю, что есть параметр -property
командной строки для ant
)
Обычно я устанавливаю различные значения в build.xml
на предполагаемые значения по умолчанию, но любой может изменить их, создав файл build.properties
.И так как все базовые свойства находятся в начале, их легко найти.
Задачи определены и в этом нецелевом пространстве.Таким образом, я легко могу найти определение, поскольку они находятся в одном и том же месте в каждом build.xml
, и я знаю, что могу использовать задачу, не беспокоясь о том, была ли достигнута цель, определяющая цель.
Теперь,на ваш вопрос:
Определите свои задачи (и у вас нет задачи по определению смолы, иначе вы сведете с ума).Затем определите зависимости для каждой из этих задач.Разработчики могут выбрать цели, которые они хотят поразить.Например:
<project>
<description>
yadda, yadda, yadda
</description>
<taskdef name="cobertura"/>
<target name="compile"
description="Compile the code"/>
<!-- Do you have to compile code before you run Cobertura?-->
<target name="coverage"
description="Calculate test coverage"
depends="compile">
<mkdir dir="${coverage.dir}"/>
<cobertura-instrument/>
</target>
<project>
Если вы хотите скомпилировать свой код, но не запускать какие-либо тесты, вы выполняете ant
с целью compile
.Если вы хотите запустить тесты, вы выполняете ant
с целью coverage
.Параметр depends=
не требуется.
Также обратите внимание на параметр description=
и задачу <description>
.Это потому, что если вы сделаете это:
$ ant -p
Ant покажет, что находится в задаче <description>
, все цели с параметром description
и это описание.Таким образом, разработчики знают, какие цели использовать для каких задач.
Кстати, я также рекомендую делать все правильно (то есть так, как я делаю) и назовите свойцели после целей жизненного цикла Maven .Зачем?Потому что это был хороший способ стандартизировать имена целей.Разработчики знают, что clean
удалит все встроенные артефакты, а compile
запустит задачу <javac>
, а test
выполнит тесты junit
.Таким образом, вы должны использовать цели в плагине Cobertura : cobertura
.
Edit
Моя проблема заключается в следующем: я рассматриваю «охват»как относящиеся к «оптимизированным» и «отладочным», т.е.Вот в чем моя трудность: для Java покрытие приводит к дополнительной промежуточной цели на этапе компиляции.
Я смотрю на страницу Corburta, и в <javac>
нет никаких реальных измененийзадача (которая является частью цели compile .
Вместо этого вы запускаете Corburtura для уже созданных .class
файлов, а затем запускаете задачу <junit>
.Большое изменение в вашей <junit>
задаче, которая теперь должна включать ссылки на ваши банки Corburtura и ваши инструментированные классы.
Я полагаю, у вас может быть цель corburtura
или как вы хотите ее называть,Эта цель запускает инструментальные тесты JUnit.Это цель, которую разработчики должны поразить, и она должна содержать описание запуска инструментальных тестов.
Конечно, вы не можете запускать инструментальные тесты Junit без предварительного инструментария.Таким образом, ваша цель corburtura
будет зависеть от другой цели instrument.tests
.Эта цель является внутренней.Люди, которые запускают ваш build.xml
, обычно не говорят «тесты приборов» без выполнения этих тестов.Таким образом, эта цель не имеет описания.
Конечно, цель instrument.tests
зависит от наличия на инструменте файлов .class
, поэтому она будет зависеть от цели compile
, которая запускает <javac>
task:
<target name="instrument.classes"
depends="compile">
<coburtura-instrument/>
</target>
<target name="corburtura"
depends="instrument.classes"
description="Runs the JUnit tests instrumented with Corburtura">
<junit/>
</target>
Единственная проблема заключается в том, что вы задаете цель <junit>
дважды: один раз при инструментировании и один раз для обычного тестирования.Это может быть незначительной проблемой.Если вы обновляете работу своих тестов JUnit, вы должны сделать это в двух местах.
Если вы хотите решить эту проблему, вы можете использовать <macrodef>
для определения теста JUnit, выполняющего макрос.Я использовал то, что было на странице Corbertura , чтобы помочь с планом.Полностью не проверен и, вероятно, полон синтаксических ошибок:
<target name="instrument.tests"
depends="compile">
<corburtura-instrument/>
</target>
<target name="corburtura"
depends="instrument.tests"
description="Instrument and run the JUnit tests">
<run.junit.test fork.flag="true">
<systemproperty.addition>
<sysproperty key="net.sourceforge.corbertura.datafile"
file="${basedir}/cobertura.ser" />
</systemproperty.addition>
<pre.classpath>
<classpath location="${instrumented.dir}" />
</pre.classpath>
<post.classpath>
<classpath refid="cobertura_classpath" />
</post.classpath>
</run.junit.test>
</target>
<target name="test"
description="Runs the Junit tests without any instrumentation">
<run.junit.test/>
</target>
<macrodef name="run.junit.test">
<attribute name="fork.flag" default="false"/>
<element name="sysproperty.addition" optional="yes"/>
<element name="pre.classpath" optional="yes"/>
<element name="post.classpath" optional="yes"/>
<sequential>
<junit fork="@{fork.flag}" dir="${basedir}" failureProperty="test.failed">
<systemproperty.addtion/>
<pre.classpath/>
<classpath location="${classes.dir}" />
<post.classpath/>
<formatter type="xml" />
<test name="${testcase}" todir="${reports.xml.dir}" if="testcase" />
<batchtest todir="${reports.xml.dir}" unless="testcase">
<fileset dir="${src.dir}">
<include name="**/*Test.java" />
</fileset>
</batchtest>
</junit>
</sequential>
</macrodef>