|
|
@@ -0,0 +1,221 @@ |
|
|
|
<?xml version="1.0"?> |
|
|
|
<!-- |
|
|
|
Copyright 2006 The Apache Software Foundation |
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
you may not use this file except in compliance with the License. |
|
|
|
You may obtain a copy of the License at |
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0 |
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software |
|
|
|
distributed under the License is distributed on an "AS IS" BASIS, |
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
|
See the License for the specific language governing permissions and |
|
|
|
limitations under the License. |
|
|
|
--> |
|
|
|
<document> |
|
|
|
|
|
|
|
<properties> |
|
|
|
<index value="1"/> |
|
|
|
<title>AntUnit</title> |
|
|
|
</properties> |
|
|
|
|
|
|
|
<body> |
|
|
|
|
|
|
|
<section name="Idea"> |
|
|
|
<p>Initially all tests for Ant tasks were written as individual |
|
|
|
<a href="http://www.junit.org/">JUnit</a> test cases. Pretty |
|
|
|
soon it was clear that most tests needed to perform common tasks |
|
|
|
like reading a build file, intializing a project instance with |
|
|
|
it and executing a target. At this point <a |
|
|
|
href="http://svn.apache.org/viewcvs.cgi/ant/core/trunk/src/testcases/org/apache/tools/ant/BuildFileTest.java">BuildFileTest</a> |
|
|
|
was invented, a base class for almost all task test cases.</p> |
|
|
|
|
|
|
|
<p>BuildFileTest works fine and in fact has been picked up by <a |
|
|
|
href="http://ant-contrib.sf.net/">the Ant-Contrib Project</a> |
|
|
|
and others as well.</p> |
|
|
|
|
|
|
|
<p>Over time a new pattern evolved, more and more tests only |
|
|
|
executed a target and didn't check any effects. Instead that |
|
|
|
target contained the assertions as a <code><fail></code> |
|
|
|
task. This is an example taken from the build file for the |
|
|
|
ANTLR task (using Ant 1.7 features):</p> |
|
|
|
|
|
|
|
<source><![CDATA[ |
|
|
|
<target name="test3" depends="setup"> |
|
|
|
<antlr target="antlr.g" outputdirectory="${tmp.dir}"/> |
|
|
|
<fail> |
|
|
|
<condition> |
|
|
|
<!-- to prove each of these files exists; |
|
|
|
ANTLR >= 2.7.6 leaves behind new (.smap) files as well. --> |
|
|
|
<resourcecount when="ne" count="5"> |
|
|
|
<fileset dir="${tmp.dir}"> |
|
|
|
<include name="CalcParserTokenTypes.txt" /> |
|
|
|
<include name="CalcParserTokenTypes.java" /> |
|
|
|
<include name="CalcLexer.java" /> |
|
|
|
<include name="CalcParser.java" /> |
|
|
|
<include name="CalcTreeWalker.java" /> |
|
|
|
</fileset> |
|
|
|
</resourcecount> |
|
|
|
</condition> |
|
|
|
</fail> |
|
|
|
</target> |
|
|
|
]]></source> |
|
|
|
|
|
|
|
<p>where the corresponding JUnit testcase has been reduced |
|
|
|
to</p> |
|
|
|
|
|
|
|
<source><![CDATA[ |
|
|
|
... |
|
|
|
public class ANTLRTest extends BuildFileTest { |
|
|
|
|
|
|
|
private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/antlr/"; |
|
|
|
|
|
|
|
public ANTLRTest(String name) { |
|
|
|
super(name); |
|
|
|
} |
|
|
|
|
|
|
|
public void setUp() { |
|
|
|
configureProject(TASKDEFS_DIR + "antlr.xml"); |
|
|
|
} |
|
|
|
|
|
|
|
public void tearDown() { |
|
|
|
executeTarget("cleanup"); |
|
|
|
} |
|
|
|
|
|
|
|
public void test3() { |
|
|
|
executeTarget("test3"); |
|
|
|
} |
|
|
|
... |
|
|
|
} |
|
|
|
]]></source> |
|
|
|
|
|
|
|
<p>This approach has a couple of advantages, one of them is that |
|
|
|
it is very easy to translate an example build file from a bug |
|
|
|
report into a test case. If you ask a user for a testcase for a |
|
|
|
given bug in Ant, he now doesn't need to understand JUnit or how |
|
|
|
to fit a test into Ant's existing tests any more.</p> |
|
|
|
|
|
|
|
<p>AntUnit takes this approach to testing even further, it |
|
|
|
removes JUnit completely and it comes with a set of predefined |
|
|
|
<code><assert></code> tasks in order to reuse common kind |
|
|
|
of checks.</p> |
|
|
|
|
|
|
|
<p>It turns out that AntUnit lends itself as a solution to other |
|
|
|
problems as well. The assertions are an easy way to validate a |
|
|
|
setup before even starting the build process, for example. |
|
|
|
AntUnit could also be used for functional and integration tests |
|
|
|
outside of the scope of Ant tasks (assert contents of databases |
|
|
|
after running an application, assert contents of HTTP responses |
|
|
|
...). This is an area that will need more research.</p> |
|
|
|
</section> |
|
|
|
|
|
|
|
<section name="Concepts"> |
|
|
|
<subsection name="antunit Task"> |
|
|
|
<p>The <antunit> task drives the tests much like |
|
|
|
<junit> does for JUnit tests.</p> |
|
|
|
|
|
|
|
<p>When called on a build file, the task will start a new Ant |
|
|
|
project for that build file and scan for targets with names |
|
|
|
that start with "test". For each such target it then will</p> |
|
|
|
<ol> |
|
|
|
<li>Execute the target named setUp, if there is one.</li> |
|
|
|
<li>Execute the target itself - if this target depends on |
|
|
|
other targets the normal Ant rules apply and the dependent |
|
|
|
targets are executed first.</li> |
|
|
|
<li>Execute the target names tearDown, if there is one.</li> |
|
|
|
</ol> |
|
|
|
|
|
|
|
</subsection> |
|
|
|
<subsection name="Assertions"> |
|
|
|
|
|
|
|
<p>The base task is <code><assertTrue></code>. It |
|
|
|
accepts a single nested condition and throws a subclass of |
|
|
|
BuildException named AssertionFailedException if that |
|
|
|
condition evaluates to false.</p> |
|
|
|
|
|
|
|
<p>This task could have been implemented using |
|
|
|
<code><macrodef></code> and <code><fail></code>, |
|
|
|
but in fact it is a "real" task so that it is possible to |
|
|
|
throw a subclass of BuildException. The |
|
|
|
<code><antunit></code> task catches this exception and |
|
|
|
marks the target as failed, any other type of Exception |
|
|
|
(including other BuildException) are test errors.</p> |
|
|
|
|
|
|
|
<p>Together with <code><assertTrue></code> there are |
|
|
|
many predefined assertions for common conditions, most of |
|
|
|
these are only macros.</p> |
|
|
|
|
|
|
|
</subsection> |
|
|
|
|
|
|
|
<subsection name="Other Tasks"> |
|
|
|
|
|
|
|
<p>The <code><logcapturer></code> captures all messages |
|
|
|
that pass Ant's logging system and provides them via a |
|
|
|
reference inside of the project. If you want to assert |
|
|
|
certain log messages, you need to start this task (prior to |
|
|
|
your target under test) and use the |
|
|
|
<code><assertLogContains></code> assertion.</p> |
|
|
|
|
|
|
|
<p><code><expectFailure></code> is a task container that |
|
|
|
catches any BuildException thrown by tasks nested into it. If |
|
|
|
no exception has been thrown it will cause a test failure (by |
|
|
|
throwing an AssertionFailedException).</p> |
|
|
|
</subsection> |
|
|
|
|
|
|
|
<subsection name="AntUnitListener"> |
|
|
|
<p>Part of the library is the <code>AntUnitListener</code> |
|
|
|
interface that can be used to record test results. The |
|
|
|
<antunit> task accepts arbitrary many listeners and |
|
|
|
relays test results to them.</p> |
|
|
|
|
|
|
|
<p>Currently only a single implementation |
|
|
|
<code><plainlistener></code> modelled after the "plain" |
|
|
|
JUnit listener is bundeled with the library.</p> |
|
|
|
</subsection> |
|
|
|
</section> |
|
|
|
|
|
|
|
<section name="Examples"> |
|
|
|
|
|
|
|
<p>This is a way to test that <code><touch></code> |
|
|
|
actually creates a file if it doesn't exist:</p> |
|
|
|
|
|
|
|
<source><![CDATA[ |
|
|
|
<project xmlns:au="antlib:org.apache.ant.antunit"> |
|
|
|
<!-- is called prior to the test --> |
|
|
|
<target name="setUp"> |
|
|
|
<property name="foo" value="foo"/> |
|
|
|
</target> |
|
|
|
|
|
|
|
<!-- is called after the test, if if that causes an error --> |
|
|
|
<target name="tearDown"> |
|
|
|
<delete file="${foo}" quiet="true"/> |
|
|
|
</target> |
|
|
|
|
|
|
|
<!-- the actual test case --> |
|
|
|
<target name="testTouchCreatesFile"> |
|
|
|
<au:assertFileDoesntExist name="${foo}"/> |
|
|
|
<touch file="${foo}"/> |
|
|
|
<au:assertFileExists name="${foo}"/> |
|
|
|
</target> |
|
|
|
</project> |
|
|
|
]]></source> |
|
|
|
|
|
|
|
<p>When running a task like</p> |
|
|
|
|
|
|
|
<source><![CDATA[ |
|
|
|
<au:antunit> |
|
|
|
<fileset dir="." includes="touch.xml"/> |
|
|
|
<au:plainlistener/> |
|
|
|
</au:antunit> |
|
|
|
]]></source> |
|
|
|
|
|
|
|
<p>from a buildfile of its own you'll get a result that looks like</p> |
|
|
|
|
|
|
|
<source><![CDATA[ |
|
|
|
]]></source> |
|
|
|
|
|
|
|
</section> |
|
|
|
</body> |
|
|
|
</document> |