[TOC]

简介

TestNG是一个旨在简化各种测试需求的测试框架,从单元测试(将一个类与其他类隔离进行测试)到集成测试(对由多个类,几个程序包甚至几个外部框架组成的整个系统进行测试),例如应用程序服务器)。

编写测试通常分为三个步骤:
编写测试的业务逻辑,然后在代码中插入TestNG注解。
在testng.xml文件或build.xml中添加有关测试的信息(例如,类名,希望运行的组等)。
运行TestNG。

您可以在“欢迎”页面上找到一个简单的示例。本文档中使用的概念如下:
suite:suite集合由一个XML文件表示。它可以包含一个或多个tests集合,并由标签定义。
test:test集合由标签表示,并且可以包含一个或多个TestNG类。
TestNG class:TestNG类相当于一个Java类,其中包含至少一个TestNG注解。它由标签表示,可以包含一个或多个测试方法。
Test method:测试方法,是在源代码中由@Test注解的Java方法。

可以通过@BeforeXXX和@AfterXXX注解配置TestNG测试,该注解允许在特定点之前和之后执行一些相同的Java逻辑,这些点是上面列出的几个项之一。本手册的其余部分将说明以下内容:
所有注解的列表,并附有简要说明。
testng.xml文件的描述,其语法以及可以在其中指定的内容。
各种功能的详细列表,以及如何通过注解和testng.xml的结合来使用它们。

Maven

<dependency>
  <groupId>org.testng</groupId>
  <artifactId>testng</artifactId>
  <version>6.8</version>
  <scope>test</scope>
</dependency>

通过mvn执行测试集
添加maven插件

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>3.0.0-M7</version>
  <configuration>
    <suiteXmlFiles>
      <suiteXmlFile>src/test/resources/run.xml</suiteXmlFile>
    </suiteXmlFiles>
  </configuration>
</plugin>

执行命令

mvn clean test -D surefire.suiteXmlFiles=run.xml

报以下错误,因为testNg版本太高,需要把jdk升级到11 55.0 -> jdk11 52.0 -> jdk8
image.png

注解

@BeforeSuite @AfterSuite @BeforeTest @AfterTest @BeforeGroups @AfterGroups @BeforeClass @AfterClass @BeforeMethod @AfterMethod TestNG类的配置信息: @BeforeSuite:带注解的方法将在suite集合中的所有测试方法运行之前运行。 @AfterSuite:带注解的方法将在运行suite集合中的所有测试之后运行。 @BeforeTest:带注解的方法将在运行任何属于标签内的类的测试方法之前运行。 @AfterTest:带注解的方法将在所有属于标记内的类的测试方法运行后运行。 @BeforeGroups:此配置方法将确保在调用属于任意这些组中的第一个测试方法之前运行。 @AfterGroups:此配置方法将确保在调用属于任意这些组中的最后一个测试方法之后运行。 @BeforeClass:带注解的方法将在调用当前类中的第一个测试方法之前运行。 @AfterClass:带注解的方法将在当前类中的所有测试方法运行之后运行。 @BeforeMethod:带注解的方法将在每个测试方法之前运行。 @AfterMethod:带注解的方法将在每个测试方法之后运行。 TestNG类的超类中注解的行为 当注解放置在TestNG类的超类上时,注解也将得到继承。这对于在一个公共超类中集中设置多个测试类非常有用。在这种情况下,TestNG将以继承顺序执行“ @Before”方法(首先是最高父类,然后沿着继承链执行),“ -After”方法以相反的顺序(沿继承链向上)执行。
alwaysRun 对于before方法(beforeSuite,beforeTest,beforeTestClass和beforeTestMethod,除了beforeGroups):如果设置为true,则无论该配置方法属于哪个组,都将运行该配置方法。 对于after方法(afterSuite,afterClass,…):如果设置为true,则即使先前调用的一个或多个方法失败或被跳过,此配置方法也将运行。
DependOnGroups 此方法所依赖的组列表。这些组之一的每个方法成员都必须在此方法之前被调用。此外,如果这些方法中的任何一个都不是SUCCESS,则该测试方法将不会运行,并将被标记为“跳过”。
dependsOnMethods 此方法所依赖的方法列表。不能保证所依赖的方法的运行顺序,但是可以保证所有这些方法都将在包含此注解的方法运行之前运行。此外,如果这些方法中的任何一个都不是SUCCESS,则该测试方法将不会运行,并将被标记为“跳过”。如果其中某些方法已重载,则将运行所有重载的版本。
enabled 是否启用了此类/方法上的方法。
groups 此类/方法所属的组的列表。例如:groups = {“1”,”2”}
inheritGroups 如果为true,则此@Configuration方法将属于在类的@Test注解中指定的组(如果有)。
firstTimeOnly /lastTimeOnly 仅适用于@BeforeMethod和@AfterMethod。如果为true且要运行的@Test方法的invocationCount大于1,则此BeforeMethod将仅被调用一次(在第一次/最后一次测试调用之前)。
description 此方法的说明。如果verbose设置 > = 2,则所使用的字符串将出现在HTML报告中,并且还会出现在标准输出中。
timeOut 此方法应花费的最大毫秒数。如果在此时间之后仍未返回,则此方法将失败,并且将导致依赖于它的测试方法被跳过。
@DataProvider 为某个测试方法提供测试数据的方法。带注解的方法必须返回一个Object [] [],可以为每个Object []分配测试方法的参数列表。想要从DataProvider接收数据的@Test方法,需要使用和此注解名称一致的dataProvider名称。
name 该数据提供者的名称。如果未提供,则此数据提供者的名称将自动设置为方法的名称。
parallel 如果设置为true,则使用此数据提供程序生成的测试用例将并发运行。默认值为false。
indices 从该数据提供者运行哪些索引,默认情况下:全部
@Factory 将方法标记为工厂,该方法将返回用于TestNG测试类的对象。该方法必须返回Object []。
dataProvider 此测试方法的dataProvider名称
dataProviderClass 在哪个类中寻找dataProvider。如果未指定,则将在当前测试方法的类或其父类之一上查找dataprovider。如果指定了此属性,则dataProvider方法在指定的类上必须是静态的。
enabled 是否启用此工厂。
@Listeners 此注解使您可以直接在测试类上定义监听器,而不是在testng.xml中定义。允许使用实现ITestNGListener接口的任何类,但IAnnotationTransformer和IAnnotationTransformer2除外,它们需要用XML定义,因为在我们开始寻找注解之前就必须知道它们。请注意,以这种方式指定的监听器对于整个suite集合是全局的,就像在testng.xml中指定的监听器一样。
value 一个继承org.testng.ITestNGListener的类的数组。
@Parameters 描述如何将参数传递给@Test方法。
value 用于填充此方法参数的变量列表。这些变量必须在testng.xml文件中定义。 例如 @Parameters({“ xmlPath”}) @Test public void verifyXmlFile(String path){…} 并在testng.xml中定义:
@Test 将类或方法标记为测试用例。
groups 此类/方法所属的组的列表。
enabled 是否启用了此类/方法上的方法。
dependsOnGroups 此方法所依赖的组列表。这些组中的每个方法都必须在此方法之前被调用。此外,如果这些方法中的任何一个都不是SUCCESS,则该测试方法将不会运行,并将被标记为“跳过”。
dependsOnMethods 此方法所依赖的方法列表。不能保证所依赖的方法的运行顺序,但是可以保证所有这些方法都将在包含此注解的测试方法运行之前运行。此外,如果这些方法中的任何一个都不是SUCCESS,则该测试方法将不会运行,并将被标记为“跳过”。如果其中某些方法已重载,则将运行所有重载的版本。
timeOut 此测试允许花费的最大毫秒数。如果在此时间后仍未返回,它将被标记为“失败”。
invocationTimeOut 此测试方法的调用总数允许花费的最大毫秒数。如果未在此方法上指定属性invocationCount,则将忽略此属性。如果在此时间后仍未返回,它将被标记为“失败”
invocationCount 调用此方法的次数。
threadPoolSize 此方法的线程池的大小。该方法将从invocationCount指定的多个线程中调用。注意:如果未指定invocationCount,则将忽略此属性
successPercentage 该方法预期成功次数占总运行次数的百分比
dataProvider 此测试方法的dataProvider名称。
dataProviderClass 在哪个类中寻找dataProvider。如果未指定,则将在当前测试方法的类或其父类之一上查找dataProvider。如果指定了此属性,则dataProvider方法在指定的类上必须是静态的。
alwaysRun 如果设置为true,则此测试方法将始终运行,即使它依赖于失败的方法也是如此。如果此测试不依赖于任何方法或组,则将忽略此属性。
description 此方法的说明。如果verbose > = 2,则所使用的字符串将出现在HTML报告中,并且还会出现在标准输出中。
expectedException 预期测试方法将引发的异常列表。如果未抛出异常或此列表中的异常,则此测试将标记为失败。
expectedExceptionsMessageRegExp 如果指定了ExpectedExceptions,则其消息必须与在此属性中指定的正则表达式匹配。
suitName 该测试类应放入的suite集合名称。如果@Test不在类级别,则忽略此属性。
testName 该测试类应放入的test集合名称。如果@Test不在类级别,则忽略此属性。
singleThreaded 如果设置为true,则即使当前正在使用parallel =“ true”运行测试,也保证该测试类上的所有方法都可以在同一线程中运行。此属性只能在类级别使用,如果在方法级别使用,则将被忽略。
retryAnalyzer 如果测试需要被重试则调用相应名称的类。 返回值:String 将测试是否应重试测试方法的类的名称。
skipFailedInvocations 如果指定true且invocationCount的值大于1,则失败后的所有调用都将被标记为SKIP而不是FAIL。
ignoreMissingDependencies 如果设置为true,则即使缺少或排除了它依赖的方法,该测试也将运行。
priority 此测试方法的优先级。优先级较低的将排在第一位。

testng.xml

可以通过几种不同的方式调用TestNG:
使用testng.xml文件
使用ant
通过命令行

本节描述了testng.xml的格式。当前testng.xml的DTD可以在主网站上找到: testng-1.0.dtd (为方便起见,您可能更喜欢浏览 HTML版本)。

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >

<!-- 配置suite集合名称 -->
<suite name="Suite1" verbose="1" >
  <!-- 配置test集合名称 -->
  <test name="Nopackage" >
    <!-- 配置要执行的测试类的名称 -->
    <classes>
      <class name="NoPackageTest" />
    </classes>
  </test>

  <!-- 配置test集合名称 -->
  <test name="Regression1">
    <classes>
      <!-- 配置要执行的测试类名称,可以配置多个测试类 -->
      <class name="test.sample.ParameterSample"/>
      <class name="test.sample.ParameterTest"/>
    </classes>
  </test>
</suite>

也可以指定要运行的包名称:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >

<suite name="Suite1" verbose="1" >
  <test name="Regression1">
    <!-- 配置要执行的包的名称,将运行这个包下面的所有测试类 -->
    <packages>
      <package name="test.sample"/>
    </packages>
  </test>
</suite>

在此示例中,TestNG将查找test.sample包中具有TestNG注解的所有类。

还可以指定要包括和排除的测试组和方法:

<test name="Regression1">
  <!-- 配置要执行的组的名称 -->
  <groups>
    <run>
      <!-- 不执行所属brokenTests组的类或方法 -->
      <exclude name="brokenTests"  />
      <!-- 执行所属checkinTests组的类或方法 -->
      <include name="checkinTests"  />
    </run>
  </groups>

  <classes>
    <!-- 配置要执行的类的名称 -->
    <class name="test.IndividualMethodsTest">
      <!-- 执行方法名称为testMethod的测试方法 -->
      <methods>
        <include name="testMethod" />
      </methods>
    </class>
  </classes>
</test>

还可以在testng.xml内定义新的组,并在属性中指定其他详细信息,例如是否并发运行测试,使用多少线程,是否运行JUnit测试等。
默认情况下,TestNG将按照在XML文件中找到的顺序运行测试。如果要以不可预测的顺序运行此文件中列出的类和方法,请将preserve-order属性设置为false

<test name="Regression1" preserve-order="false">
  <classes>

    <class name="test.Test1">
      <methods>
        <include name="m1" />
        <include name="m2" />
      </methods>
    </class>

    <class name="test.Test2" />

  </classes>
</test>

TestNG.xml DTD

DTD介绍:文档类型定义(DTD)

<!--

这是此DTD主要部分的快速概述。更多信息,请查阅testng主页http://testng.org

suite 标签是由 tests 标签和 parameters 标签组成的。

test 标签是由三部分组成:
1、parameters 会覆盖 suite 标签中的 parameters;
2、groups 由2部分组成:
    2.1、Definitions,允许你将 groups 添加到更大的 groups 中
    2.2、Runs,定义了此 test集合 要运行的方法必须属于这个组
3.classes 定义了此test集合运行时包含的类。

-->


<!-- 标签是一个testng.xml文件中最高级的元素 -->
<!ELEMENT suite (listeners|packages|test|parameter|method-selectors|suite-files)* >(注释:声明suite元素,元素可出现0或多次)

<!-- 属性: -->
<!--
@attr  name        此suite集合的名称 (此名称将会出现在报告中)
@attr  junit       是否以 JUnit 模式运行。
@attr  verbose     控制台输出的完整程度。这个设置对于HTML报告没有影响。
@attr  parallel    TestNG将使用什么方式来并发运行测试(可能会减少运行时间)。
@attr  configfailurepolicy   在Before/After Class/Methods失败之后继续进行尝试或
                             者是跳过
@attr  thread-count   一个整型,如果你设置了并发,使用这个值来确定使用的线程池的大小。
@attr  annotations    如果是"javadoc", TestNG将会在你的资源中查找JavaDoc注解,
                      否则使用JDK5的注解。
@attr  time-out   在method(如果parallel="methods")或test(如果parallel="te
                  sts")结束前等待的毫秒数。
@attr  skipfailedinvocationcounts     是否跳过失败的调用。
@attr  data-provider-thread-count     一个整型,确定用于data providers并发的线程
                                      池大小。
@attr  object-factory     一个类,实现了IObjectFactory类,将用于实例化test对象。
-->

<!ATTLIST suite 
name CDATA #REQUIRED    (注释:#REQUIRED表示必填)
junit (true | false) "false"(注释:枚举值,可选:true|false,默认值"false")
verbose CDATA #IMPLIED    (注释:#IMPLIED表示非必填)
parallel (false | methods | tests | classes) "false"
configfailurepolicy (skip | continue) "skip"
thread-count CDATA "5"
annotations CDATA #IMPLIED
time-out CDATA #IMPLIED
skipfailedinvocationCounts (true | false) "false"
data-provider-thread-count CDATA "10"
object-factory CDATA #IMPLIED
>


<!-- XML文件列表,包含了更多suite集合的说明 -->
<!ELEMENT suite-files (suite-file)* >

<!ELEMENT suite-file ANY > (注释:元素suite-file可以是任何内容)
<!ATTLIST suite-file
path CDATA #REQUIRED
>


<!--
Parameters可以在<suite>或者<test>级别定义,在<test>中定义的参数将覆盖<suite>中定义的同名参数

Parameters用于将Java方法参数链接到此处定义的实际值。
-->
<!ELEMENT parameter ANY>
<!ATTLIST parameter
name CDATA #REQUIRED
value CDATA #REQUIRED >


<!--
方法选择器定义用于选择要运行的方法的用户类。这些类需要实现org.testng.IMethodSelector接口。
-->
<!ELEMENT method-selectors (method-selector*) >

<!ELEMENT method-selector ((selector-class)*|script) >
<!ELEMENT selector-class ANY>
<!ATTLIST selector-class
name CDATA #REQUIRED
priority CDATA #IMPLIED
>
<!ELEMENT script ANY>
<!ATTLIST script
language CDATA #REQUIRED
>


<!--
一个test集合包含parameters和classes。此外,你可以定义额外的组("groups的groups") 
-->
<!ELEMENT test (method-selectors?,parameter*,groups?,packages?,classes?) >
(注释:子元素使用逗号(“,”)隔开,表示子元素需要按照相同的顺序出现在文档中)
<!--
@attr  name         此test的名称 (此名称将会出现在报告中)
@attr  junit        是否以 JUnit 模式运行。
@attr  verbose      控制台输出的完整程度。这个设置对于HTML报告没有影响。
                    默认值:suite中定义的verbose级别。
@attr  parallel     TestNG将使用什么方式来并发运行测试(可能会减少运行时间)。
@attr  thread-count 一个整型,如果使用并发模式以此确定使用的线程池大小。
                    覆盖suite中设置的值。
@attr  annotations  如果是"javadoc", TestNG将会在你的资源中查找JavaDoc注解,
                    否则使用JDK5的注解。
@attr  time-out     在method(如果parallel="methods")或test(如果parallel=
                    "tests")结束前等待的毫秒数。
@attr  enabled      当前test的启用/禁用标志。默认值是:true。
@attr  skipfailedinvocationCounts     是否跳过失败的调用.
-->
<!ATTLIST test
name CDATA #REQUIRED 
junit (true | false) "false"
verbose  CDATA #IMPLIED
parallel  CDATA #IMPLIED
thread-count CDATA #IMPLIED
annotations  CDATA #IMPLIED
time-out CDATA #IMPLIED
enabled CDATA #IMPLIED
skipfailedinvocationCounts (true | false) "false"
>


<!--
定义额外的组("groups的groups")并且指定此test集合运行时应包含哪些组。
-->
<!ELEMENT groups (define*,run?) >

<!ELEMENT define (include*)>

<!ATTLIST define 
name CDATA #REQUIRED>
<!-- 定义要包括在当前组中的组  -->
<!ELEMENT include ANY>
<!ATTLIST include
name CDATA #REQUIRED>
<!-- 定义要从当前组中排除的组  -->
<!ELEMENT exclude ANY>
<!ATTLIST exclude
name CDATA #REQUIRED>

<!-- 组的子标签,用于定义要运行的组  -->
<!ELEMENT run (include?,exclude?)* >

<!-- 此test中包含的类列表  -->
<!ELEMENT classes (class*) >
<!ELEMENT class (methods*) >
<!ATTLIST class
name CDATA #REQUIRED >

<!-- 此test中包含的包列表  -->
<!ELEMENT packages (package*) >
<!-- 包的说明。如果包名称以.* 结尾,则还将包含子程序包  -->
<!ELEMENT package (include?,exclude?)*>
<!ATTLIST package
name CDATA #REQUIRED >

<!-- 此测试包括/排除的方法列表 -->
<!ELEMENT methods (include?,exclude?)* >

<!-- 将传递给TestNG的监听器列表 -->
<!ELEMENT listeners (listener*) >

<!ELEMENT listener ANY>
<!ATTLIST listener
    class-name CDATA #REQUIRED >

运行TestNG

可以通过不同的方式调用TestNG:
命令行
Ant
Eclipse
IntelliJ’s IDEA

假设类路径中有TestNG,则调用TestNG的最简单方法如下: :::danger TODO 实际会报错找不到类 org.testng.TestNG,因为是通过maven导入的包,所以类路径下估计找不到 :::

java org.testng.TestNG testng1.xml [testng2.xml testng3.xml ...]

需要至少指定一个XML文件来描述要运行的TestNG suite。此外,可以使用以下命令行选项:
可以通过不带任何参数的TestNG调用来获取此文档

命令行参数
选项 入参 参数说明
-configfailurepolicy skip|continue 如果@ Before *方法失败,则TestNG是继续执行suit中的其余测试,还是跳过它们。默认skip。
-d 目录 指定生成报告的所在目录(默认为test-output)。
-dataproviderthreadcount 多线程运行测试时供数据驱动使用的默认线程数。 设置多线程运行测试时供数据驱动使用的默认最大线程数。如果多线程模式已被选择(例如,与-parallel选项)它才会生效。这可以在suit定义中覆盖。
-excludegroups 组列表(以逗号分隔)。 要排除的组的列表。
-groups 组列表(以逗号分隔)。 要运行的组的列表(例如“ windows,linux,regression”)。
-listener 在类路径中存在的Java类的列表(以逗号分隔)。 可以指定自己的测试监听器。这些类需要实现org.testng.ITestListener
-usedefaultlisteners true|false 是否使用默认监听器
-methods 完全限定的类名称和方法的列表(以逗号分隔)。例如com.example.Foo.f1,com.example.Bar.f2。 可以指定要运行的单个方法。
-methodselectors Java类和方法优先级列表(以逗号分隔),用于定义方法选择器。 可以在命令行上指定方法选择器。例如: com.example.Selector1:3, com.example.Selector2:2
-parallel methods|tests|classes 用于设置运行测试时如何使用多线程的机制。如果未设置,则默认机制是不使用多线程运行。这可以在suit定义中覆盖。
-reporter 自定义报告器的扩展配置。 与-listener选项类似,不同之处在于它允许在报告器实例上配置JavaBeans样式的属性。 示例:-reporter com.test.MyReporter:methodFilter = insert ,enableFiltering = true 每添加一个报告器对应一个这个选项。
-sourcedir 目录列表(用分号分隔)。 用Javadoc注解的测试源的目录。仅当您使用javadoc类型注解时,才需要此选项。(例如“ src / test”或“ src / test / org / testng / eclipse-plugin; src / test / org / testng / testng”)。
-suitename 测试suite的默认名称。 指定了在命令行上定义的测试suite的名称。如果suite.xml文件或源代码指定了不同的suite名称,则将忽略此选项。如果将suite名称用双引号“ like this”引起来,则可以创建一个带有空格的suite名称。
-testclass 可以在类路径中找到的类列表(逗号分隔)。 用逗号分隔的类文件列表(例如“ org.foo.Test1,org.foo.test2”)。
-testjar 一个jar文件。 指定一个包含测试类的jar文件。如果在该jar文件的根目录下找到了testng.xml文件,则将使用该文件,否则,在此jar文件中找到的所有测试类都将被视为测试类。
-testname test的默认名称。 指定了在命令行上定义的test名称。如果suite.xml文件或源代码指定其他test名称,则忽略此选项。如果将test名称用双引号“ like this”括起来,可以在其中创建一个带有空格的test名称。
-testnames 以逗号分隔的test名称列表。 仅运行在标记中定义的与这些名称之一匹配的测试。
-testrunfactory 可以在类路径中找到的Java类。 指定自己的测试运行工厂。该类需要实现org.testng.ITestRunnerFactory。
-threadcount 多线程运行测试时要使用的默认线程数。 设置用于多线程运行测试的默认最大线程数。如果多线程模式已被选择(例如,与-parallel选项)它才会生效。可以在suite定义中覆盖。
-xmlpathinjar jar文件中XML文件的路径。 此属性应包含测试jar中有效XML文件的路径(例如“ resources / testng.xml”)。默认值为“ testng.xml”,这意味着在jar文件的根目录下有一个名为“ testng.xml ”的文件。除非指定了-testjar,否则该选项将被忽略。

还可以将命令行参数放在文本文件中,例如c:\ command.txt,并告诉TestNG使用该文件来检索其参数:

Plain Text
C:> more c:\command.txt
-d test-output testng.xml
C:> java org.testng.TestNG @c:\command.txt

此外,可以在Java虚拟机的命令行上传递TestNG属性,例如

Java
java -Dtestng.test.classpath=”c:/build;c:/java/classes;” org.testng.TestNG testng.xml

这是TestNG可以理解的属性:

属性 类型 文档
testng.test.classpath 用分号分隔的一系列目录,其中包含测试类。 如果设置了此属性,TestNG将使用它来查找测试类,而不是类路径。如果在XML文件中使用package标签,并且在类路径中有很多类,而其中大多数不是测试类,这将很方便。

例子:

Nginx
java org.testng.TestNG -groups windows,linux -testclass org.test.MyTest

ant任务testng.xml可以使用更多的参数来启动TestNG(包含的方法,包括指定参数,等…),所以只有当你了解TestNG或者想快速运行测试时才使用命令行。
重要提示:如果在testng.xml文件中指定了要运行的测试,则忽略命令行指定的那些测试,除了-includedgroups和-excludedgroups,它将覆盖所有testng.xml中发现的要包含/排除的组。

测试方法,测试类和测试组

测试方法

测试方法用@Test注解。除非在testng.xml中将allow-return-values设置为true,否则将忽略@Test注解方法的返回值:

XML
<suite allow-return-values=”true”>

or

<test allow-return-values=”true”>

测试组

TestNG允许对测试方法进行复杂的分组。不仅可以声明方法属于组,还可以指定组里面包含其他的组。然后可以指定包含特定组的集合(或正则表达式),来调用TestNG。如果想连续的运行2个不同的测试集合,这将提供最大的灵活性来划分测试方式,且不需要重新编译任何内容。

例如,至少有两类测试是很普遍的
冒烟测试。在提交新代码之前,应先运行这些测试。它们通常跑的很快,并且只需确保没有破坏任何基本功能即可。
功能测试。这些测试应涵盖软件的所有功能,并且每天至少要运行一次,尽管理想情况下,希望连续运行它们。
通常,冒烟测试是功能测试的子集。TestNG允许通过测试组以非常直观的方式进行指定。

例如,可以通过指定所有的测试类都应属于“ functest”组来构造测试,另外,还有几个方法属于“ checkintest”组:

Java
public class Test1 {

@Test(groups = {“functest”,”checkintest”})
public void testMethod1() {
}

@Test(groups = {“functest”,”checkintest”} )
public void testMethod2() {
}

@Test(groups = {“functest”})
public void testMethod3() {
}
}

TestNG.xml

XML
<test name=”Test1”>
<groups>
<run>

<include name=”functest”/>
</run>
</groups>
<classes>
<class name=”example1.Test1”/>
</classes>
</test>

将运行Test1类中的所有测试方法,如果使用“checkintest”组调用,将仅运行testMethod1()和testMethod2()。

这是另一个示例,这次使用正则表达式。假设某些测试方法不应在Linux上运行,则测试方法应如下所示:

Java
@Test
public class Test1 {
@Test(groups = {“windows.checkintest”})
public void testWindowsOnly() {
}

@Test(groups = {“linux.checkintest”} )
public void testLinuxOnly() {
}

@Test(groups = {“windows.functest”)
public void testWindowsToo() {
}
}

可以使用以下testng.xml仅启动Windows方法:

XML
<test name=”Test1”>
<groups>
<run>
<include name=”windows.“/>
</run>
</groups>

<classes>
<class name=”example1.Test1”/>
</classes>
</*test
>

注意:TestNG使用正则表达式,而不使用wildmats。注意区别(例如,“ anything”由“.”(点星号)而不是“ ”匹配)。

方法组

还可以排除或包括单个方法:

XML
<test name=”Test1”>
<classes>
<class name=”example1.Test1”>
<methods>
<include name=”.enabledTestMethod.“/>
<exclude name=”.brokenTestMethod.“/>
</methods>
</class>
</classes>
</test>

这可以方便地停用单个方法而无需重新编译任何东西,但是不建议过多使用此方式,因为如果开始重构Java代码,该测试框架很可能会被破坏(标签可能不再与方法匹配)。

小组分组

组也可以包括其他组。这些组称为“ MetaGroups”。例如,可能想定义一个包括“ checkintest”和“ functest”的“ all”组。“ functest”本身将包含“ windows”和“ linux”组,而“ checkintest将仅包含” windows”。这是在xml文件中定义的方式:

XML
<test name=”Regression1”>
<groups>

<define name=”functest”>
<include name=”windows”/>
<include name=”linux”/>
</define>


<define name=”checkintest”>
<include name=”windows”/>
</define>


<define name=”all”>
<include name=”functest”/>
<include name=”checkintest”/>
</define>

<run>
<include name=”all”/>
</run>
</groups>

<classes>
<class name=”test.sample.Test1”/>
</classes>
</test>

排除组

TestNG允许运行时包括或不包括组。
例如,由于最近的更改而使测试暂时中断,但是还没有时间对中断进行修复。但是需要其余功能测试能继续运行,因此需要停用这些出现问题的测试用例。(但是要记得将修复后的用例重新激活)
解决这个问题的一种简单方法是创建一个名为“broken”的组,并将这些有问题的测试方法标记属于这个组。例如,在上面的示例中,testMethod2() 现在出现问题,因此想禁用它:

Java
@Test(groups = {“checkintest”,”broken”} )
public void testMethod2() {
}

现在要做的就是从运行的test集合中排除该组:

XML
<test name=”Simple example”>
<groups>
<run>
<include name=”checkintest”/>
<exclude name=”broken”/>
</run>
</groups>

<classes>
<class name=”example1.Test1”/>
</classes>
</test>

这样,将进行继续运行其余用例的测试,同时跟踪哪些测试出现问题并且后续进行修复。
注意:也可以通过使用@Test和@ Before / After注解的“ enabled”是否可用属性来禁用测试方法。

部分组

Java
@Test(groups = {“checkin-test”})
public class All {

@Test(groups = {“func-test”)
public void method1() { … }

public void method2() { … }
}

在此类中,method2()是“ checkin-test”组的一部分,该组在类级别定义,而method1()既属于“ checkin-test”组又属于“ func-test”组。

参数

测试方法不必是无参数的。可以在每个测试方法上使用任意数量的参数,并通过使用TestNG的@Parameters注解传递正确的参数。
设置这些参数的方法有两种:使用testng.xml或以代码方式设置。

来自testng.xml的参数

如果参数是简单的值,可以在testng.xml中指定:

Java
@Parameters({“first-name”})
@Test
public void testSingleString(String firstName) {
System.out.println(“Invoked testString “+ firstName);
assert“Cedric”.equals(firstName);
}

在此代码中,指定testSingleString()方法的参数firstName接收名为first-name的XML参数的值 此XML参数在testng.xml中通过定义:

XML
<suite name=”My suite”>
<parameter name=”first-name” value=”Cedric”/>
<test name=”Simple example”>
<— … —>

同样适用于@ Before / After和@Factory注解:

Java
@Parameters({“datasource”,”jdbc-driver”})
@BeforeMethod
public void beforeTest(String ds, String driver) {
m_dataSource = …;
m_jdbcDriver = driver;
}

这次,两个Java参数dsdriver将分别取属性datasource和jdbc-driver赋予的值。

可以使用Optional注解将参数声明为可选

Java
@Parameters(“db”)
@Test
public void testNonExistentParameter(@Optional(“mysql”) String db) { … }

如果在testng.xml文件中找不到名为“ db”的参数,则测试方法将使用@Optional注解里指定的默认值:“ mysql”。
@Parameters 注解可以被放置在下列位置:
在任何已经具有@Test,@ Before / After或@Factory注解的方法上。
在测试类的最多一个构造函数上。在这种情况下,每当需要实例化测试类时,TestNG就会使用testng.xml中指定的参数的值来调用特定的构造函数。此功能可用于将类中的字段初始化为供测试方法使用的值。
XML参数将以它们在注解中发现的顺序映射到Java参数上,如果参数的数量不匹配,TestNG会报错。
参数是有作用域的。在testng.xml中,可以在或者标签下声明参数。如果两个参数具有相同的名称,则以中定义的优先。如果需要指定一个适用于所有测试的参数,并且仅对某些测试覆盖,这将非常方便。

数据驱动的参数

在testng.xml中指定参数可能不能够传递复杂的参数或需要由Java创建的参数(复杂对象,从属性文件或数据库读取的对象等)。在这种情况下,可以使用数据驱动来提供测试需要的值。数据驱动是类里的一种方法,它返回一个对象数组的数组。这个方法使用@DataProvider注解:

Java
// 声明一个名为“test1”的数据驱动方法为任意的测试方法提供数据
@DataProvider(name =”test1”)
public Object[][] createData1() {
return new Object[][] {
{“Cedric”, new Integer(36) },
{“Anne”, new Integer(37)},
};
}


// 测试方法声明它的数据是由“test1”这个数据驱动方法来提供的
@Test(dataProvider =”test1”)
public void verifyData1(String n1, Integer n2) {
System.out.println(n1 +” “+ n2);
}

上面的程序将打印

Apache
Cedric 36
Anne 37

@Test 方法通过dataProvider属性指定了使用的数据驱动方法。名称必须与同个类底下使用@DataProvider(name =“ …”)注解的方法一致。
默认情况下,会在当前测试类或它的父类中查找数据驱动方法。如果要将数据提供程序放在不同的类中,则必须是静态方法或是无参数构造函数的类,并在dataProviderClass属性中指定可被找到的类路径:

Java

public class StaticProvider {
@DataProvider(name =”create”)
public static Object[][] createData() {
return new Object[][] {
new Object[] { new Integer(42) }
};
}
}

public class MyTest {
@Test(dataProvider =”create”, dataProviderClass = StaticProvider.class)
public void test(Integer n) {
// …
}
}

数据驱动也支持注入。TestNG将使用测试上下文进行注入。数据驱动方法可以返回以下类型之一:
对象数组的数组(Object [] []),第一维的数组是调用测试方法的次数,第二维的数组包含必须与测试方法的参数类型兼容的对象数组。上面的示例说明了这种情况。
Iterator。与Object [] []的唯一区别是,迭代器可以延迟创建测试数据。TestNG调用迭代器,然后迭代器依次返回测试方法的参数。如果有很多参数集要传递给方法又不想预先创建所有参数集,可以使用这个方法。
对象数组(Object [])。类似于Iterator ,但会导致源数组的每个元素都会调用一次测试方法。
Iterator >。Object []的延迟替代方法。导致迭代器的每个元素调用一次测试方法。
必须说的是,返回类型不仅限于Object,因此MyCustomData [] []或Iterator 也是可以的。唯一的限制是,在使用迭代器的情况下,其参数类型本身无法明确地参数化。这是此功能的示例:

Java
@DataProvider(name =”test1”)
public Iterator createData() {
return new MyIterator(DATA);
}

使用MyCustomData []作为返回类型

Java
@DataProvider(name =”test1”)
public MyCustomData[] createData() {
return new MyCustomData[]{ new MyCustomData() };
}

或它的Iterator 的延迟选项

Java
@DataProvider(name =”test1”)
public Iterator createData() {
return Arrays.asList(new MyCustomData()).iterator();
}

无法明确参数化Iterator的参数类型(Stream)

Java
@DataProvider(name =”test1”)
public Iterator createData() {
return Arrays.asList(Stream.of(“a”,”b”,”c”)).iterator();
}

如果声明的@DataProvider以java.lang.reflect.Method作为第一个参数,则TestNG将传递当前测试方法作为第一个参数。这个功能可以用在以下场景:当多个测试方法使用相同的@DataProvider且希望根据不同的测试方法提供不同的测试数据。
例如,以下代码在@DataProvider中打印了测试方法的名称:

Java
@DataProvider(name =”dp”)
public Object[][] createData(Method m) {
// 打印测试方法名
System.out.println(m.getName());
return new Object[][] {new Object[] {“Cedric”}};
}

@Test(dataProvider =”dp”)
public void test1(String s) {
}

@Test(dataProvider =”dp”)
public void test2(String s) {
}

并且将会打印

Prolog
test1
test2

数据驱动可以使用属性parallel多线程运行:

Java
@DataProvider(parallel =true)
// …

一个XML文件运行的多线程数据驱动共享相同的线程池,默认情况下,线程池的大小为10。可以在XML文件的标签中修改这个值:

Java
<suite name=”Suite1” data-provider-thread-count=”20”>

如果要在其他线程池中运行一些特定的数据驱动,则需要从其他XML文件运行。

报告中的参数

TestNG生成的HTML报告中显示了用于调用测试方法的参数。这是一个例子:
TestNG - 图2

依赖关系

有时候,需要按特定顺序调用测试方法。这里有一些例子:
在运行更多测试方法之前,确保一定数量的测试方法已经完成并成功。
期望初始化方法作为测试方法的同时初始化测试(用@ Before / After标记的方法将不属于最终报告的一部分)。
TestNG允许使用注解或XML来指定依赖项

用注解建立用例间的依赖关系

可以使用@Test注解的dependsOnMethods或dependsOnGroups属性。
有两种依赖关系:
硬依赖。依赖的所有方法都必须已运行并运行成功。如果依赖项中有失败,将不会调用并且在报告中会标记为SKIP。
软依赖。即使其中某些方法失败了,也将在依赖的方法之后运行。当只想确保测试方法按特定顺序执行,但它们运行是否成功并不取决于其他方法的成功时使用。通过在@Test直接中添加“ alwaysRun = true”来使用软依赖。
这是一个硬依赖性的示例:

Java
@Test
public void serverStartedOk() {}

@Test(dependsOnMethods = {“serverStartedOk”})
public void method1() {}

在此示例中,method1()被声明为依赖于方法serverStartedOk(),在调用method1()时会先调用serverStartedOk()。

还可以使方法依赖于整个组:

Java
@Test(groups = {“init”})
public void serverStartedOk() {}

@Test(groups = {“init”})
public void initEnvironment() {}

@Test(dependsOnGroups = {“init.“})
*public void
method1() {}

在此示例中,method1()被声明为依赖于与正则表达式“ init.*”匹配的所有组,在method1()调用之前会调用serverStartedOk()和initEnvironment()方法。
注意:如前所述,在测试过程中无法保证属于同一组的方法的调用顺序是相同的。

如果依赖的方法失败并且有硬依赖关系(默认设置alwaysRun = false),则依赖于该方法的测试方法不会标记为FAIL,而是会标记为SKIP。跳过的方法也记录在最后的报告中(在HTML中既不是红色也不是绿色),这是因为跳过的方法不一定会失败。

dependsOnGroups和dependsOnMethods都可以使用正则表达式作为参数。对于dependsOnMethods,如果依赖的一个方法发生了多次的重载,所有重载方法将重新调用。如果只想调用重载方法中的一个,则应使用dependsOnGroups。

有关依赖方法的更高级示例,请参阅这篇文章,该文章使用继承为多重依赖问题提供了一种优雅的解决方案。

默认情况下,依赖方法按类分组。例如,如果b()方法依赖于a()方法,并且有多个类的实例包含了这些方法(由于数据驱动的工厂),则调用顺序如下:

Apache
a(1)
a(2)
b(2)
b(2)

TestNG在所有实例都调用a()方法之前,不会运行b()。
在某些情况下(例如,测试各个国家/地区的Web浏览器登录和注销),不希望出现以上的行为。在这种情况下,需要执行以下排序:

Java
signIn(“us”)
signOut(“us”)
signIn(“uk”)
signOut(“uk”)

对于此排序,可以使用XML的group-by-instances属性。此属性在上有效:

XML
<suite name=”Factory” group-by-instances=”true”>
or
<test name=”Factory” group-by-instances=”true”>

XML中的依赖关系

或者,可以在testng.xml文件中指定组的依赖。可以使用标签来实现此目的:

XML
<test name=”My suite”>
<groups>
<dependencies>
<group name=”c” depends-on=”a b”/>
<group name=”z” depends-on=”c”/>
</dependencies>
</groups>
</test>

属性包含以空格分隔的组列表。

工厂

工厂可以用来动态创建测试。例如,假设想创建一个测试方法,该方法将多次访问网站上的页面,并且希望使用不同的值来调用它:

Java
public class TestWebServer {
@Test(parameters = {“number-of-times”})
public void accessPage(int numberOfTimes) {
while(numberOfTimes— > 0) {
// access the web page
}
}
}
XML



<class name=”TestWebServer”/>






<class name=”TestWebServer”/>






<class name=”TestWebServer”/>

这将很快就变得无法管理,因此,应该使用工厂:

Java
public class WebTestFactory {
@Factory
public Object[] createInstances() {
Object[] result = new Object[10];
for(inti =0; i <10; i++) {
result[i] = new WebTest(i 10);
}
*return
result;
}
}

现在新的测试类是:

Java
public class WebTest {
private int m_numberOfTimes;
public WebTest(int numberOfTimes) {
m_numberOfTimes = numberOfTimes;
}

@Test
public void testServer() {
for(inti =0; i < m_numberOfTimes; i++) {
// access the web page
}
}
}

testng.xml只需要引用包含工厂方法的类,因为测试实例本身将在运行时创建:

XML
<class name=”WebTestFactory”/>

或者,如果以编程方式构建测试suite实例,则可以按照与测试相同的方式添加工厂:

Java
TestNG testNG = new TestNG();
testNG.setTestClasses(WebTestFactory.class);
testNG.run();

工厂方法可以像@Test和@ Before / After一样接收参数,并且必须返回Object []。返回的对象可以是任何类(不一定与工厂类相同),甚至不需要包含TestNG注解(在这种情况下,TestNG将忽略它们)。
工厂也可以与数据驱动一起使用,并且可以通过将@Factory注解放在常规方法或构造函数上来利用此功能。这是构造函数工厂的示例:

Java
@Factory(dataProvider =”dp”)
public FactoryDataProviderSampleTest(int n) {
super(n);
}

@DataProvider
static public Object[][] dp() {
return new Object[][] {
new Object[] {41},
new Object[] {42},
};
}

该示例将使TestNG创建两个测试类,依次使用41和42调用构造函数。

类级别的注解

@Test注解也可以放在类上面:

Java
@Test
public class Test1 {
public void test1() {
}

public void test2() {
}
}

类级别的@Test注解的作用是使该类的所有公共方法都成为测试方法,即使没有被注解。如果要添加某些属性,仍然可以在方法上重复添加@Test注解。
例如:

Java
@Test
public class Test1 {
public void test1() {
}

@Test(groups =”g1”)
public void test2() {
}
}

test1()和test2()都是测试方法,但是test2()额外属于“ g1”组。

忽略测试

TestNG可以忽略所有@Test方法:
在一个类里(或)
在一个特定包中(或)
在一个包及其所有子包中

使用注解@Ignore。
在方法级别使用时,@ Ignore注解在功能上等效于@Test(enabled = false)。这是一个示例,显示了如何忽略类中的所有测试。

Java
import org.testng.annotations.Ignore;
import org.testng.annotations.Test;

@Ignore
public class TestcaseSample {

@Test
public void testMethod1() {
}

@Test
public void testMethod2() {
}
}

@Ignore注解具有比@Test方法注解更高的优先级。将@Ignore放在一个类上时,该类中的所有测试都将被禁用。
要忽略特定程序包中的所有测试,只需创建package-info.java并向其添加@Ignore批注。这是一个示例:

Java
@Ignore
package com.testng.master;

import org.testng.annotations.Ignore;

这将忽略com.testng.master包及其所有子包中的所有@Test方法。

多线程和超时

可以让TestNG以各种方式在单独的线程中运行测试。
标签的parallell属性可以取下列的值:

XML
<suite name=”My suite” parallel=”methods” thread-count=”5”>
<suite name=”My suite” parallel=”tests” thread-count=”5”>
<suite name=”My suite” parallel=”classes” thread-count=”5”>
<suite name=”My suite” parallel=”instances” thread-count=”5”>

parallel =“ methods”:TestNG将在单独的线程中运行所有测试方法。依赖方法也将在单独的线程中运行,但是它们将遵循指定的顺序。
parallel =“ tests”:TestNG将在同一线程中的运行同一标签中的所有方法,但是每个标签将位于单独的线程中。这使您可以将所有不是线程安全的类归入同一中,并确保它们都将在同一线程中运行,同时利用TestNG使用尽可能多的线程来运行测试。
parallel =“ classes”:TestNG将在同一线程中运行同一类中的所有方法,但是每个类将在单独的线程中运行。
parallel =“ instances”:TestNG将在同一线程中的同一实例中运行所有方法,但是两个不同实例中的两个方法将在不同线程中运行。
此外,thread-count 属性可以指定应为此执行分配多少个线程。
注意:@Test属性timeOut在多线程和非多线程模式下均可工作。

还可以指定从不同的线程调用一个@Test方法。可以使用threadPoolSize属性来实现:

Java
@Test(threadPoolSize =3, invocationCount =10, timeOut =10000)
public void testServer() {

在此示例中,将从三个不同的线程调用函数testServer十次。此外,十秒的超时保证没有任何线程永远阻塞该线程。

重新运行失败的测试

每当suite中的测试失败时,TestNG都会在输出目录中创建一个名为testng-failed.xml的文件。该XML文件包含必要的信息,以重新运行这些失败的方法,从而快速重现失败,而不必运行整个测试。因此,典型的做法如下所示:

Perl
java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -d test-outputs testng.xml
java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -d test-outputs test-outputs\testng-failed.xml

注意,testng-failed.xml将包含所有必需的依赖方法,因此可以确保运行失败的方法不会因出现任何失败而SKIP。

有时,可能希望TestNG在测试失败时自动重试。在这种情况下,可以使用重试分析器。将重试分析器绑定到一个测试上时,TestNG会自动调用重试分析器,以确定TestNG是否可以再次重试测试用例,以查看刚刚失败的测试现在是否通过。这是使用重试分析器的方法:
构建一个实现了org.testng.IRetryAnalyzer接口的类
将此实现绑定到@Test注解,例如@Test(retryAnalyzer = LocalRetry.class)
以下是重试分析器实现的示例,最多重试一个测试三次。

Java
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;

public class MyRetry implements IRetryAnalyzer {

private int retryCount =0;
private static final int maxRetryCount =3;

@Override
public boolean retry(ITestResult result) {
if(retryCount < maxRetryCount) {
retryCount++;
return true;
}
return false;
}
}
Java
import org.testng.Assert;
import org.testng.annotations.Test;

public class TestclassSample {

@Test(retryAnalyzer = MyRetry.class)
public void test2() {
Assert.fail();
}
}

JUnit测试

TestNG可以运行JUnit 3和JUnit 4测试。所需要做的就是把JUnit的jar文件放在类路径中,然后在testng.classNames属性中指定JUnit测试类并且将testng.junit属性设置为true:

XML
<test name=”Test1” junit=”true”>
<classes>

在这种情况下,TestNG的行为类似于JUnit,这取决于在类路径上找到的JUnit版本:
JUnit 3:
类中所有以test *开头的方法都将运行
如果测试类上有一个setUp()方法,将在每个测试方法之前调用
如果测试类上有一个tearDown()方法,将在每个测试方法之后被调用
如果测试类包含suite()方法,则将调用此方法返回的所有测试
JUnit 4:
TestNG将使用org.junit.runner.JUnitCore程序运行测试

以编程方式运行TestNG

可以很容易地从自己的程序中调用TestNG:

Java
TestListenerAdapter tla = new TestListenerAdapter();
TestNG testng = new TestNG();
testng.setTestClasses(new Class[] { Run2.class });
testng.addListener(tla);
testng.run();

本示例创建了一个TestNG对象并运行测试类Run2。还添加了一个TestListener。也可以使用适配器类org.testng.TestListenerAdapter或自己实现org.testng.ITestListener。此接口包含了各种回调方法,可跟踪测试的开始,成功,失败等。

同样,可以通过testng.xml文件调用TestNG,也可以自己创建一个虚拟的testng.xml文件。为此,可以使用org.testng.xml包的类:XmlClassXmlTest等。这些类中的都可以匹配对应的XML标签。
例如,要创建以下虚拟文件:

XML



<class name=”test.failures.Child”/>


使用以下代码:

Java
XmlSuite suite = new XmlSuite();
suite.setName(“TmpSuite”);

XmlTest test = new XmlTest(suite);
test.setName(“TmpTest”);
List classes = new ArrayList();
classes.add(new XmlClass(“test.failures.Child”));
test.setXmlClasses(classes) ;

然后,可以将此XmlSuite传递给TestNG:

Java
List suites = new ArrayList();
suites.add(suite);
TestNG tng = new TestNG();
tng.setXmlSuites(suites);
tng.run();

有关完整的API,请参阅JavaDocs

BeanShell和高级组选择

如果testng.xml中的标签不足以满足您的需要,则可以使用BeanShell表达式来确定是否应在测试运行中包括某种测试方法。可以在标签下指定此表达式:

XML
<test name=”BeanShell test”>
<method-selectors>
<method-selector>
<script language=”beanshell”>
<![CDATA[groups.containsKey(“test1”)]]>
</script>
</method-selector>
</method-selectors>

当在testng.xml中找到