|
- <?xml version="1.0"?>
- <!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You 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="AntUnit 1.1">
- <h3>September 26, 2008 - Apache AntUnit 1.1 Released</h3>
-
- <p>Apache AntUnit 1.1 is now available for download as <a
- href="http://ant.apache.org/antlibs/bindownload.cgi">binary</a>
- or <a
- href="http://ant.apache.org/antlibs/srcdownload.cgi">source</a>
- release.</p>
-
- <p>In addition to a few bugfixes and some new assertions AntUnit
- 1.1 allows test listeners to receive the log output of the
- project under test. Both plainlistener and xmllistener have
- an option that makes them echo the project's output into their
- respective logs.</p>
- </section>
-
- <section name="AntUnit 1.1 Beta 1">
- <h3>September 3, 2008 - Apache AntUnit 1.1 Beta 1 Available</h3>
- </section>
-
- <section name="AntUnit 1.0">
- <h3>January 8, 2007 - Apache AntUnit 1.0 Available</h3>
-
- <p>Apache AntUnit 1.0 is now available for download as <a
- href="http://ant.apache.org/antlibs/bindownload.cgi">binary</a>
- or <a
- href="http://ant.apache.org/antlibs/srcdownload.cgi">source</a>
- release.</p>
-
- </section>
-
- <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, initializing 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 two implementations -
- <code><plainlistener></code> and <code>xmllistener</code>
- modelled after the "plain" and "xml"
- JUnit listeners - are bundled 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, even if that caused an error -->
- <target name="tearDown">
- <delete file="${foo}" quiet="true"/>
- </target>
-
- <!-- the actual test case -->
- <target name="testTouchCreatesFile">
- <au:assertFileDoesntExist file="${foo}"/>
- <touch file="${foo}"/>
- <au:assertFileExists file="${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[
- [au:antunit] Build File: /tmp/touch.xml
- [au:antunit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.249 sec
- [au:antunit] Target: testTouchCreatesFile took 0.183 sec
-
- BUILD SUCCESSFUL
- Total time: 1 second
- ]]></source>
-
- </section>
- </body>
- </document>
|