JUnit

描述

此任务运行来自 JUnit 测试框架的测试。该框架的最新版本可以在 https://junit.java.net.cn 找到。此任务已在 JUnit 3.0 到 JUnit 3.8.2 上测试过;它不适用于 JUnit 3.0 之前的版本。它也适用于 JUnit 4.x,包括仅使用注解且不使用 JUnit4TestAdapter 的“纯”JUnit 4 测试。

注意:此任务依赖于 Apache Ant 分发版中未包含的外部库。有关更多信息,请参见 库依赖项

注意:如果此任务启动的测试或测试使用的任何库调用了诸如 java.lang.System.exit()java.lang.Runtime.exit() 之类的 API,则必须设置 fork=true

注意:您必须拥有 junit.jar。您可以执行以下操作之一:

  1. junit.jarant-junit.jar 都放在 ANT_HOME/lib 中。
  2. 不要将它们放在 ANT_HOME/lib 中,而是将它们的位置包含在您的 CLASSPATH 环境变量中。
  3. 使用 -lib 将这两个 JAR 添加到您的类路径中。
  4. 使用构建文件中的 <taskdef> 中的 <classpath> 元素指定这两个 JAR 的位置。
  5. ant-junit.jar 保留在 ANT_HOME/lib 中的默认位置,但将 junit.jar 包含在传递给 <junit><classpath> 中。从 Ant 1.7 开始

有关详细信息,请参见 常见问题解答

测试由嵌套的 testbatchtest 标签定义(请参见 嵌套元素)。

参数

属性 描述 必需
printsummary 为每个测试用例打印单行统计信息。可以取值 onoffwithOutAndErrwithOutAndErron 相同,但还包括测试写入 System.outSystem.err 的输出。 否;默认值为 off
fork 在单独的 JVM 中运行测试。 否;默认值为 off
forkmode 控制如果您想分叉一些测试,将创建多少个 JVM。可能的值是 perTest(默认值)、perBatchonceonce 仅为所有测试创建一个 JVM,而 perTest 为每个 TestCase 类创建一个新的 JVM。 perBatch 为每个嵌套的 <batchtest> 创建一个 JVM,并创建一个收集所有嵌套的 <test> 的 JVM。请注意,只有具有相同 filtertracehaltonerrorhaltonfailureerrorpropertyfailureproperty 设置的测试才能共享一个 JVM,因此即使您将 forkmode 设置为 once,Ant 也可能必须创建多个 JVM。此属性将被忽略,因为测试不会分叉到新的 JVM 中。从 Ant 1.6.2 开始 否;默认值为 perTest
haltonerror 如果在测试运行期间发生错误,则停止构建过程。 否;默认值为 off
errorproperty 在发生错误时要设置的属性的名称。
haltonfailure 如果测试失败(错误也被视为失败),则停止构建过程。 否;默认值为 off
failureproperty 在发生失败(错误也被视为失败)时要设置的属性的名称。
filtertrace 从错误和失败堆栈跟踪中过滤掉 JUnit 和 Ant 堆栈帧。 否;默认值为 on
timeout 如果单个测试在给定时间内(以毫秒为单位)未完成,则取消该测试。如果 forkoff,则忽略此项。在同一 JVM 中运行多个测试(请参见 forkMode)时,timeout 适用于所有测试一起使用的时间,而不是单个测试。
maxmemory 分配给分叉 JVM 的最大内存量。如果 forkoff,则忽略此项。注意:如果您在某些测试中遇到 java.lang.OutOfMemoryError: Java heap space,则需要提高大小,例如 maxmemory=128m
jvm 用于调用 JVM 的命令。该命令由 java.lang.Runtime.exec() 解析。 否;默认值为 java,如果 forkfalse,则忽略此项
dir 在其中调用 JVM 的目录。 否,如果 forkfalse,则忽略此项
newenvironment 在指定新的环境变量时,不要传播旧环境。 否;默认值为 false,如果 forkfalse,则忽略此项
includeantruntime 在分叉模式下,将隐式地将运行测试所需的 Ant 类和 JUnit 添加到类路径中。 否;默认值为 true
showoutput 将测试生成的任何输出发送到 Ant 的日志系统以及格式化程序。 否;默认情况下,只有格式化程序会收到输出
outputtoformatters 将测试生成的任何输出发送到测试格式化程序。从 Ant 1.7.0 开始 否;默认值为 true
tempdir Ant 应放置临时文件的位置。从 Ant 1.6 开始 否;默认值为项目的 basedir
reloading 是否应为每个测试用例实例化一个新的类加载器。
如果 fork 设置为 true,则忽略此项。从 Ant 1.6 开始
否;默认值为 true
clonevm 如果设置为 true,则分叉 JVM 的所有系统属性和 bootclasspath 将与运行 Ant 的 JVM 的系统属性和 bootclasspath 相同。从 Ant 1.7 开始 否;默认值为 false,如果 forkfalse,则忽略此项
logfailedtests 当 Ant 执行多个测试并且不会在错误或失败时停止时,它会将其日志系统中的每个失败测试的“FAILED”消息记录下来。如果您将此选项设置为 false,则不会记录该消息,您必须依靠格式化程序输出来查找失败的测试。从 Ant 1.8.0 开始
enableTestListenerEvents Ant 是否应将有关正在运行的测试的细粒度信息发送到 Ant 的日志系统,处于详细级别。自定义测试侦听器可以使用此类事件来显示测试的进度。
从 Ant 1.8.2 开始Ant 1.7.0 到 1.8.1 的行为就好像此属性默认情况下为 true 一样。
否;默认值为 false,可以由 神奇属性 覆盖
threads 运行测试的线程数。
当指定此属性时,测试将被任意地拆分到线程中。
要求测试使用 perTest 选项分叉才能生效。
从 Ant 1.9.4 开始

通过使用 errorpropertyfailureproperty 属性,可以执行设置工作(例如启动外部服务器)、执行测试、清理,并且在发生失败时仍然使构建失败。

filtertrace 属性在报告错误和失败堆栈跟踪之前会压缩它们。它适用于普通格式化程序和 XML 格式化程序。它会过滤掉以以下字符串模式开头的任何行:

   "junit.framework.TestCase"
   "junit.framework.TestResult"
   "junit.framework.TestSuite"
   "junit.framework.Assert."
   "junit.swingui.TestRunner"
   "junit.awtui.TestRunner"
   "junit.textui.TestRunner"
   "java.lang.reflect.Method.invoke("
   "sun.reflect."
   "org.apache.tools.ant."
   "org.junit."
   "junit.framework.JUnit4TestAdapter"
   " more"

作为嵌套元素指定的参数

<junit> 任务支持一个嵌套的 <classpath> 元素,它表示一个 类似路径的结构

从 Ant 1.7 开始,此类路径可用于引用 junit.jar 以及您的测试和被测试的代码。

jvmarg

如果 forktrue,则可以通过嵌套的 <jvmarg> 元素将其他参数传递给新的 JVM。例如

<junit fork="yes">
  <jvmarg value="-Dfoo=bar"/>
  ...
</junit>

将在没有 JIT 的 JVM 中运行测试。

<jvmarg> 允许 命令行参数 中描述的所有属性。

sysproperty

使用嵌套的 <sysproperty> 元素来指定类所需的系统属性。这些属性将在测试执行期间(在 Ant 的 JVM 或分叉的 JVM 中,如果 fork=true)提供给 JVM。此元素的属性与 环境变量 的属性相同。

<junit fork="no">
  <sysproperty key="basedir" value="${basedir}"/>
  ...
</junit>

将在 Ant 的 JVM 中运行测试,并将 basedir 属性提供给测试。

syspropertyset

从 Ant 1.6 开始

您可以使用 syspropertyset 指定一组用作系统属性的属性。

env

可以通过嵌套的 <env> 元素指定要传递给分叉 JVM 的环境变量。有关 <env> 元素属性的描述,请参见 exec 任务中的描述。

如果 fork=false,则设置将被忽略。

bootclasspath

从 Ant 1.6 开始.

可以使用此 类似路径的结构 指定引导类文件的位置—如果 forkfalse 或目标 JVM 不支持它(即 Java 1.1),则将被忽略。

permissions

从 Ant 1.6 开始.

注意:
在 Java 18 及更高版本上运行时,此元素不再受支持。有关详细信息,请参见 permissions

可以通过嵌套的 permissions 元素在类执行期间撤销和授予安全权限。有关更多信息,请参见 permissions

如果 fork=true,则设置将被忽略。

assertions

从 Ant 1.6 开始.

您可以使用 <assertions> 子元素来控制 Java 1.4 断言的启用。

断言语句目前在非分叉模式下被忽略。

modulepath

从 Ant 1.9.8 开始

可以使用此 类似路径的结构 指定模块的位置。
modulepath 要求 fork 设置为 true

upgrademodulepath

从 Ant 1.9.8 开始

可以使用此 类似路径的结构 指定替换运行时映像中可升级模块的模块的位置。
upgrademodulepath 要求 fork 设置为 true

formatter

测试结果可以用不同的格式打印。输出始终会发送到文件,除非您将 usefile 属性设置为 false。文件名称由测试名称确定,可以通过 <test>outfile 属性设置。

有四个预定义的格式化程序—一个以 XML 格式打印测试结果,另一个发出纯文本。名为 brief 的格式化程序只打印失败测试用例的详细信息,而 plain 为所有测试用例提供一个简短的统计信息行。可以指定需要实现 org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter 的自定义格式化程序。

如果您使用 XML 格式化程序,它可能不包含测试写入的相同输出,因为某些字符在 XML 文档中是非法的,将被删除。

第四个名为 failure 的格式化程序(从 Ant 1.8.0 开始)收集所有失败的 testXXX() 方法,并创建一个新的 TestCase,它只委托这些失败的方法。名称和位置可以通过 Java 系统属性或 Ant 属性 ant.junit.failureCollector 指定。该值必须指向结果类的目录和名称(不带后缀)。它默认为 java-tmp-dir/FailedTests

属性 描述 必需
type 使用预定义的格式化程序(xmlplainbrieffailure)。 这些中只有一个
classname 自定义格式化程序类的名称。
extension 要附加到输出文件名中的扩展名。 是,如果已使用 classname
usefile 确定是否应将输出发送到文件的布尔值。 否;默认值为 true
if 仅在 命名属性已设置 时使用格式化程序。 否;默认值为 true
unless 仅在 命名属性设置 时使用格式化程序。 否;默认值为 true

test

定义单个测试类。

属性 描述 必需
name 测试类的名称。
methods 要执行的测试用例方法的逗号分隔名称列表。自 1.8.2 起

methods 属性在以下场景中很有用

  • 测试方法失败,您想重新运行测试方法以测试修复程序或在 Java 调试器下重新运行测试,而无需等待其他(可能运行时间很长)测试方法完成。
  • 一个或多个测试方法的运行速度比预期慢,您想在 Java 分析器下重新运行它们(无需在执行其他测试方法时运行分析器的开销)。

如果使用了 methods 属性但未指定测试方法,则不会执行套件中的任何测试方法。

否;默认情况下运行套件中的所有测试方法
fork 在单独的 JVM 中运行测试。覆盖在 <junit> 中设置的值。
haltonerror 如果在测试运行期间发生错误,则停止构建过程。覆盖在 <junit> 中设置的值。
errorproperty 发生错误时要设置的属性的名称。覆盖在 <junit> 中设置的值。
haltonfailure 如果测试失败(错误也被视为失败),则停止构建过程。覆盖在 <junit> 中设置的值。
failureproperty 发生故障(错误也被视为故障)时要设置的属性的名称。覆盖在 <junit> 中设置的值。
filtertrace 从错误和故障堆栈跟踪中过滤掉 JUnit 和 Ant 堆栈帧。覆盖在 <junit> 中设置的值。 否;默认值为 on
todir 要将报告写入的目录。 否;默认值为当前目录
outfile 测试结果的基名称。完整文件名是 outfile.formatter 否;默认值为 TEST-name
if 仅在 设置了命名属性 时运行测试。
unless 仅在 设置命名属性 时运行测试。
skipNonTests 不要将任何不包含 JUnit 测试的类传递给测试运行器。这可以防止非测试在测试结果中显示为测试错误。
通过在不扩展 junit.framework.TestCase 的具体类中的任何方法上查找 @Test 注释,或通过在扩展 junit.framework.TestCase 的具体类中查找以 test 开头的公共/受保护方法来识别测试。标记有 JUnit 4 org.junit.runner.RunWithorg.junit.runner.Suite.SuiteClasses 注释的类也会传递给 JUnit 以执行,与任何具有公共/受保护的无参数 suite() 方法的类一样。
否;默认值为 false

测试可以通过嵌套的 <formatter> 元素定义自己的格式化程序。

batchtest

根据模式匹配定义一定数量的测试。

batchtest 收集来自任何数量的嵌套 资源集合 的包含的 资源。然后,它为每个以 .java.class 结尾的资源生成一个测试类名。

任何类型的资源集合都支持作为嵌套元素,在 Ant 1.7 之前,仅支持 <fileset>

属性 描述 必需
fork 在单独的 JVM 中运行测试。覆盖在 <junit> 中设置的值。
haltonerror 如果在测试运行期间发生错误,则停止构建过程。覆盖在 <junit> 中设置的值。
errorproperty 发生错误时要设置的属性的名称。覆盖在 <junit> 中设置的值。
haltonfailure 如果测试失败(错误也被视为失败),则停止构建过程。覆盖在 <junit> 中设置的值。
failureproperty 发生故障(错误也被视为故障)时要设置的属性的名称。覆盖在 <junit> 中设置的值
filtertrace 从错误和故障堆栈跟踪中过滤掉 JUnit 和 Ant 堆栈帧。覆盖在 <junit> 中设置的值。 否;默认值为 on
todir 要将报告写入的目录。 否;默认值为当前目录
if 仅在 设置了命名属性 时运行测试。
unless 仅在 设置命名属性 时运行测试。
skipNonTests 不要将任何不包含 JUnit 测试的类传递给测试运行器。这可以防止非测试在测试结果中显示为测试错误。
通过在不扩展 junit.framework.TestCase 的具体类中的任何方法上查找 @Test 注释,或通过在扩展 junit.framework.TestCase 的具体类中查找以 test 开头的公共/受保护方法来识别测试。标记有 JUnit 4 org.junit.runner.RunWithorg.junit.runner.Suite.SuiteClasses 注释的类也会传递给 JUnit 以执行,与任何具有公共/受保护的无参数 suite() 方法的类一样。
否;默认值为 false

批处理测试可以通过嵌套的 <formatter> 元素定义自己的格式化程序。

分叉测试和 tearDown()

如果分叉测试遇到超时,Ant 将终止它创建的 JVM 进程,这可能意味着测试的 tearDown() 方法永远不会被调用。如果分叉 JVM 因其他原因崩溃,情况也是如此。

自 Ant 1.8.0 起,Ant 附带了一个特殊的格式化程序,它尝试加载分叉 JVM 中的测试用例并调用该类的 tearDown() 方法。此格式化程序具有以下限制

如果格式化程序识别出不兼容的 forkModesuite() 方法或无法加载测试类,它将静默地不执行任何操作。

格式化程序对未分叉或未导致超时或 JVM 崩溃的测试没有任何影响。

要启用格式化程序,请添加一个 formatter,例如

<formatter classname="org.apache.tools.ant.taskdefs.optional.junit.TearDownOnVmCrash"
           usefile="false"/>

到您的 junit 任务中。

ant.junit.enabletestlistenerevents 魔法属性

自 Ant 1.8.2 起,任务的 enableTestListenerEvents 属性控制是否将细粒度日志消息发送到任务的详细日志。除了此属性之外,Ant 还将查询属性 ant.junit.enabletestlistenerevents,并且属性的值将覆盖属性的设置。

此属性的存在是为了让运行 Ant 的容器(依赖于附加日志事件)能够确保即使构建文件禁用了这些事件,它们也会生成。

示例

在同一个 VM 中运行在 my.test.TestCase 中定义的测试。除非测试失败,否则不会生成任何输出。

<junit>
    <test name="my.test.TestCase"/>
</junit>

在单独的 JVM 中运行在 my.test.TestCase 中定义的测试。在测试结束时,将打印一行摘要。测试的详细报告可以在 TEST-my.test.TestCase.txt 中找到。如果测试失败,构建过程将停止。

<junit printsummary="yes" fork="yes" haltonfailure="yes">
    <formatter type="plain"/>
    <test name="my.test.TestCase"/>
</junit>

在同一个 JVM 中运行 my.test.TestCase,忽略给定的 CLASSPATH;如果此测试失败,只会打印警告。除了纯文本测试结果之外,对于此测试,将输出一个 XML 结果到 result.xml。然后,对于 ${src.tests} 定义的目录中的每个匹配文件,将在单独的 JVM 中运行一个测试。如果测试失败,构建过程将中止。结果将收集在名为 TEST-name.txt 的文件中,并写入 ${reports.tests}

<junit printsummary="yes" haltonfailure="yes">
    <classpath>
        <pathelement location="${build.tests}"/>
        <pathelement path="${java.class.path}"/>
    </classpath>

    <formatter type="plain"/>

    <test name="my.test.TestCase" haltonfailure="no" outfile="result">
        <formatter type="xml"/>
    </test>

    <batchtest fork="yes" todir="${reports.tests}">
        <fileset dir="${src.tests}">
            <include name="**/*Test*.java"/>
            <exclude name="**/AllTests.java"/>
        </fileset>
    </batchtest>
</junit>

在第一次运行时,所有测试都通过 <batchtest/> 元素收集。它的 plain 格式化程序在控制台上显示输出。 failure 格式化程序在 ${build.dir}/failingTests/FailedTests.java 中创建一个 Java 源文件,它扩展了 junit.framework.TestCase 并从 suite() 方法返回失败测试的测试套件。
在第二次运行时,收集器类存在,并且代替 <batchtest/>,将运行单个 <test/>。因此,只重新运行失败的测试用例。两个嵌套的格式化程序用于显示(供用户使用)和更新收集器类。

<target name="test">
    <property name="collector.dir" value="${build.dir}/failingTests"/>
    <property name="collector.class" value="FailedTests"/>
    <!-- Delete 'old' collector classes -->
    <delete>
        <fileset dir="${collector.dir}" includes="${collector.class}*.class"/>
    </delete>
    <!-- compile the FailedTests class if present -->
    <javac srcdir="${collector.dir}" destdir="${collector.dir}"/>
    <available file="${collector.dir}/${collector.class}.class" property="hasFailingTests"/>
    <junit haltonerror="false" haltonfailure="false">
        <sysproperty key="ant.junit.failureCollector" value="${collector.dir}/${collector.class}"/>
        <classpath>
            <pathelement location="${collector.dir}"/>
        </classpath>
        <batchtest todir="${collector.dir}" unless="hasFailingTests">
            <fileset dir="${collector.dir}" includes="**/*.java" excludes="**/${collector.class}.*"/>
            <!-- for initial creation of the FailingTests.java -->
            <formatter type="failure"/>
            <!-- I want to see something ... -->
            <formatter type="plain" usefile="false"/>
        </batchtest>
        <test name="FailedTests" if="hasFailingTests">
            <!-- update the FailingTests.java -->
            <formatter type="failure"/>
            <!-- again, I want to see something -->
            <formatter type="plain" usefile="false"/>
        </test>
    </junit>
</target>

在由 platform.java 属性给出的分叉 JVM 中,将 my.test.TestCase 作为白盒测试运行。JUnit 库是未命名模块的一部分,而被测项目和必需模块位于模块路径上。测试没有模块信息文件,并在由 module.name 属性给出的项目模块中执行。
--patch-module Java 选项在由 module.name 属性给出的模块中执行构建到 ${build.test.classes} 中的测试。
--add-modules Java 选项启用被测模块。
--add-reads Java 选项使包含 JUnit 的未命名模块可被被测模块读取。
--add-exports Java 选项使未导出的测试包 my.test 可从包含 JUnit 的未命名模块访问。

<junit fork="true"
       jvm="${platform.java}">
    <jvmarg line="--patch-module ${module.name}=${build.test.classes}"/>
    <jvmarg line="--add-modules ${module.name}"/>
    <jvmarg line="--add-reads ${module.name}=ALL-UNNAMED"/>
    <jvmarg line="--add-exports ${module.name}/my.test=ALL-UNNAMED"/>
    <classpath>
        <pathelement path="${libs.junit}"/>
    </classpath>
    <modulepath>
        <pathelement path="${modules}:${build.classes}"/>
    </modulepath>
    <formatter type="plain"/>
    <test name="my.test.TestCase"/>
</junit>

在由 platform.java 属性给出的分叉 JVM 中,将 my.test.TestCase 作为黑盒测试运行。JUnit 库用作自动模块。测试的模块信息需要被测模块和 JUnit。
--add-modules Java 选项启用测试模块。
--add-exports Java 选项使未导出的测试包 my.test 可从 JUnit 模块和 Ant 的测试运行器访问。另一种可能性是在测试的模块信息中通过 exports my.test 指令导出测试包。

<junit fork="true"
       jvm="${platform.java}">
    <jvmarg line="--add-modules ${test.module.name}"/>
    <jvmarg line="--add-exports ${test.module.name}/my.test=junit,ALL-UNNAMED"/>
    <modulepath>
        <pathelement path="${modules}:${build.classes}:${libs.junit}"/>
    </modulepath>
    <formatter type="plain"/>
    <test name="my.test.TestCase"/>
</junit>