【转】TestNG使用详解 一、testng 介绍 二、@Test注解及常用属性 三、testng常用注解 四、testng.xml 配置文件详解 五、testng 中方法参数传递 六、testng 多线程测试

【转】TestNG使用详解
一、testng 介绍
二、@Test注解及常用属性
三、testng常用注解
四、testng.xml 配置文件详解
五、testng 中方法参数传递
六、testng 多线程测试

TestNG 是一个测试框架,其灵感来自 JUnit 和 NUnit,但同时引入了一些新的功能,使其功能更强大,使用更方便。

TestNG 设计涵盖所有类型的测试:单元,功能,端到端,集成等,它需要 JDK5 或更高的 JDK 版本。

详细使用说明请参考官方链接:https://testng.org/doc/index.html

在 maven 中引入依赖:

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>6.10</version>
</dependency>

简单示例:

(1)被测试 HelloWorld 类

package study.testng;

public class HelloWorld {

    public String hello(){
        return "hello world !";
    }
}

(2)测试类 TestHelloWorld 类

package study.testng;

import org.testng.Assert;
import org.testng.annotations.Test;

public class TestHelloWorld {

    //测试返回结果不为空
    @Test
    public void tester1(){
        HelloWorld hello = new HelloWorld();
        String helloworld = hello.hello();

        Assert.assertNotNull(helloworld);
    }
    
    //测试返回结果为”hello world !“字符串
    @Test
    public void tester2(){
        HelloWorld hello = new HelloWorld();
        String helloworld = hello.hello();
        System.out.println(helloworld);

        Assert.assertEquals(helloworld, "hello world !");
    }
}

(3)测试结果

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml

hello world !

===============================================
Default Suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================


凡是在类方法中添加了 @Test 注解的就是我们需要测试的方法


默认是 true , 如果设置为 false ,则在运行时不会执行这个测试方法;

示例:

package com.ggf.testng.annotation;

import org.testng.annotations.Test;

/**
 * @Description: 忽略测试,可以通过@Test的注解的enable属性来配置是否执行用例方法
 * enable默认值为 true,需要设置为false才会跳过这个测试用例
 * @Author: ggf
 * @Date: 2019/12/29
 */
public class IgnoreTest {
    @Test
    public void ignore1() {
        System.out.println("ignore1 run...");
    }

    @Test(enabled = false)
    public void ignore2() {
        System.out.println("ignore2 run ...");
    }

    @Test
    public void ignore3() {
        System.out.println("ignore3 run ...");
    }
}

运行结果:

 
[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml
ignore1 run...
ignore3 run ...
===============================================
Default Suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================


@Test(expectedExceptions = ClassName.class)
如果 ClassName 类抛出了异常,测算测试通过,没有异常算测试不通过;

expectedExceptions的值也可以是一个数组:
@Test(expectedExceptions = {ClassName.class, ClassName2.class,... })

示例:

package com.ggf.testng.annotation;

import org.testng.annotations.Test;

/**
 * @Description:  异常测试
 * @Author: ggf
 * @Date: 2019/12/29
 *
 * 什么时候会用到异常测试??
 * 在我们期望结果为某一个异常的时候
 * 比如:我们传入了某些不合法的参数,程序抛出了异常
 * 也就是说我的期望结果就是这个异常。
 */
public class ExpectedException {
    /**
     * 运行时异常,我们期望返回一个运行时异常,这条用例才是正确的。
     */
    @Test(expectedExceptions = RuntimeException.class, enabled = false)
    public void runTimeExceptionFailed() {
        System.out.println("没有抛出异常,这条用例不通过!");
    }

    /**
     * 结果抛出了一个运行时异常,和我们的期望一致,测试通过。
     */
    @Test(expectedExceptions = RuntimeException.class)
    public void runTimeExceptionSuccess() {
        System.out.println("程序抛出了运行时异常,测试用例通过!");
        throw new RuntimeException();
    }

}

运行结果:

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml
程序抛出了运行时异常,测试用例通过!
===============================================
Default Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================


在被依赖的方法运行完成之后运行当前方法,如果依赖方法测试不通过,那么当前方法也不会继续运行了;依赖的方法可以有多个;

例:@Test(dependsOnMethods = { "methodName1" , “methodName2” })

示例:

 
package com.ggf.testng.annotation;

import org.testng.annotations.Test;

/**
 * @Description: 方法直接的依赖测试
 * @Author: ggf
 * @Date: 2019/12/29
 */
public class DependTest {
    @Test
    public void test1() {
        System.out.println("test1 run ...");
    }

    /**
     * test2运行时,需要依赖test1的运行
     * 如果test1运行失败,会直接忽略test2, test2就不会执行了。
     */
    @Test(dependsOnMethods = {"test1"})
    public void test2() {
        System.out.println("test2 run ...");
    }
}


  • 把在一个<test>标签内的中所有类方法再进行组,在运行时,一个组的方法会一起运行,然后再运行下一个组的方法;

  • 分组的最小维度为方法,当把带分组的@Test(groups = ”groupName”)注解对类使用时,这个测试类中的所有方法都属于这同一个组;

  • 一个方法也可以同时属于多个组,@Test(groups = {“groupName1”, “groupName2”}),那么每组运行时这个方法都会被执行一次;

  • 同一个组里的方法类,如果分别属于两个不同的测试用例(<test>)内,那么它们其实可以算两个组,它们会在每个测试用例分别运行,而不会合在一起运行;

示例:

package com.ggf.testng.groups;

import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;

import javax.sound.midi.Soundbank;

/**
 * @Description: 对测试用例方法进行分组,可以对一组中的数据进行初始化
 * @Author: ggf
 * @Date: 2019/12/29
 */
public class GroupsOnMethod {
    @BeforeGroups(groups = "server")
    public void beforeGroupsOnServer() {
        System.out.println("服务端组运行前执行的方法。。。");
    }

    @BeforeGroups(groups = "client")
    public void beforeGroupsOnClient() {
        System.out.println("客户端组运行前执行的方法。。。");
    }

    @Test(groups = "server")
    public void test1() {
        System.out.println("server test1 run ....");
    }

    @Test(groups = "server")
    public void test2() {
        System.out.println("server test2 run ....");
    }

    @Test(groups = "client")
    public void test3() {
        System.out.println("client test3 run ....");
    }

    @Test(groups = "client")
    public void test4() {
        System.out.println("client test4 run ....");
    }

    @AfterGroups(groups = "server")
    public void afterGroupsOnServer() {
        System.out.println("服务端组运行之后执行的方法。。。");
    }

    @AfterGroups(groups = "client")
    public void afterGroupsOnClient() {
        System.out.println("客户端组运行之后执行的方法。。。");
    }
}

运行结果:

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml
  
服务端组运行前执行的方法。。。
server test1 run ....
server test2 run ....
服务端组运行之后执行的方法。。。


客户端组运行前执行的方法。。。
client test3 run ....
client test4 run ....
客户端组运行之后执行的方法。。。

===============================================
Default Suite
Total tests run: 4, Failures: 0, Skips: 0
===============================================


@Test(timeOut = 3000) 设置超时时间,单位为毫秒。

示例:

package com.course.testng;

import org.testng.annotations.Test;

public class TimeOutTest {

    /**
     * 单位为毫秒值,3秒内没有响应,就证明失败了,反之成功
     * @throws InterruptedException
     */
    @Test(timeOut = 3000)
    public void testSuccess() throws InterruptedException {
        Thread.sleep(2000);
    }

    @Test(timeOut = 2000)
    public void testFailed() throws InterruptedException {
        Thread.sleep(3000);
    }
}

运行结果:

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml

org.testng.internal.thread.ThreadTimeoutException: Method com.course.testng.TimeOutTest.testFailed() didn't finish within the time-out 2000

===============================================
Default Suite
Total tests run: 2, Failures: 1, Skips: 0
===============================================


属性名 描述
alwaysRun 设置为 true 时,无论什么情况都会运行
dataProvider 数据提供者的名称
dataProviderClass 如果未指定,将在当前测试方法的类或其父类之一上查找数据提供者。 如果指定了此属性,则数据提供者方法在指定的类上必须是静态的。
dependsOnGroups 依赖的组列表
dependsOnMethods 依赖的方法列表
description 说明
enabled 默认为true,设置为 false 时失效
expectedExceptions 预期测试方法将引发的异常列表。 如果未引发任何异常或与该列表中的异常不同,则此测试将标记为失败。
groups 所属组
invocationCount 调用次数
invocationTimeOut 所有 invocationCount 的累积超时时间。 注意:如果未指定 nvocationCount,则将忽略此属性。
priority 此测试方法的优先级
successPercentage 该方法预期成功的百分比
singleThreaded 如果设置为 rue,则即使当前正在使用 parallel =“ methods” 运行测试,也保证该测试类上的所有方法都可以在同一线程中运行。 此属性只能在类级别使用,如果在方法级别使用,则将被忽略。
timeOut 超时时间
threadPoolSize 此方法的线程池的大小。 该方法将从 invocationCount 指定的多个线程中调用。 注意:如果未指定 invocationCount,则忽略此属性


注解 描述
@BeforeSuite 在该套件的所有测试都运行在注释的方法之前,仅运行一次(套件测试是一起运行的多个测试类)。
@AfterSuite 在该套件的所有测试都运行在注释方法之后,仅运行一次。
@BeforeClass 在调用当前类的第一个测试方法之前运行,注释方法仅运行一次。
@AfterClass 在调用当前类的第一个测试方法之后运行,注释方法仅运行一次。
@BeforeTest 注释的方法将在属于<test>标签内的类的所有测试方法运行之前运行。
@AfterTest 注释的方法将在属于<test>标签内的类的所有测试方法运行之后运行。
@BeforeGroups 配置方法将在之前运行组列表。 此方法保证在调用属于这些组中的任何一个的第一个测试方法之前不久运行。
@AfterGroups 此配置方法将在之后运行组列表。该方法保证在调用属于任何这些组的最后一个测试方法之后不久运行。
@BeforeMethod 注释方法将在每个测试方法之前运行。
@AfterMethod 注释方法将在每个测试方法之后运行。
@Parameters 描述如何将参数传递给@Test方法。
@DataProvider 标记一种方法来提供测试方法的数据。 注释方法必须返回一个Object [] [],其中每个Object []可以被分配给测试方法的参数列表。 要从该DataProvider接收数据的@Test方法需要使用与此注释名称相等的dataProvider名称。
@Factory 将一个方法标记为工厂,返回TestNG将被用作测试类的对象。 该方法必须返回Object []。
@Listeners 定义测试类上的侦听器。
@Test 将类或方法标记为测试的一部分。

示例:

测试类 TestConfig.java

package study.testng;

import org.testng.annotations.AfterGroups;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class TestConfig {

    @BeforeSuite
    public void beforeSuite() {
        System.out.println("测试套件(当前xml中<suite>标签)之前运行@BeforeSuite--------------------");
    }

    @AfterSuite
    public void afterSuite() {
        System.out.println("测试套件(当前xml中<suite>标签)之后运行@AfterSuite--------------------
");
    }

    @BeforeTest
    public void beforeTest() {
        System.out.println("测试用例(当前xml中<test>标签)之前运行@BeforeTest----------");
    }

    @AfterTest
    public void afterTest() {
        System.out.println("测试用例(当前xml中<test>标签)之后运行@AfterTest----------
");
    }
    
    @BeforeMethod
    public void beforeMethod() {
        System.out.println("当前类每个测试方法(@Test)之前运行@BeforeMethod");
    }
    
    @AfterMethod
    public void AfterMethod(){
        System.out.println("当前类每个测试方法(@Test)之后运行@AfterMethod");
    }
    
    @BeforeGroups(value="group1")
    public void beforeGroups(){
        System.out.println("配置组配group1之前运行@BeforeGroups..................");
    }
    @AfterGroups(value="group1")
    public void afterGroups(){
        System.out.println("配置组配group1之前运行@AfterGroups..................");
    }
    
    @Test
    public void test1(){
        System.out.println("runnig TestConfig.test1()");
    }
    
    @Test(groups = "group1")
    public void test2(){
        System.out.println("runnig TestConfig.test2()");
    }
    
    @Test(groups = "group1")
    public void test3(){
        System.out.println("runnig TestConfig.test3()");
    }
    
}

新建一个自定义 xml 配置文件 tester.xml (maven项目将该文件创建在 resource 目录下)

<?xml version="1.0" encoding="UTF-8"?>

<!-- @BeforeSuite -->
<suite name="tester">

    <!-- @BeforeTest -->
    <test name="case1">
      <classes>
        <class name="study.testng.TestConfig" />
        <class name="study.testng.TestHelloWorld" />
      </classes>
    </test>
    <!-- @AfterTest -->
    
    <!-- @BeforeTest -->
    <test name="case2">
      <classes>
        <class name="study.testng.TestConfig" />
      </classes>
    </test>
    <!-- @AfterTest -->

</suite>
<!-- @AfterSuite -->

运行结果:

【转】TestNG使用详解
一、testng 介绍
二、@Test注解及常用属性
三、testng常用注解
四、testng.xml 配置文件详解
五、testng 中方法参数传递
六、testng 多线程测试

从这个结果显示出注释的作用位置。其中 @BeforeGroups 和 @AfterGroups 的作用范围是可以跨类的,但类必须是在同一个测试用例(<test>标签)范围内;

这些标签的运行先后顺序可以总结为:

@BeforeSuite->@BeforeTest->@BeforeClass->{@BeforeMethod->@Test->@AfterMethod}->@AfterClass->@AfterTest->@AfterSuite(其中{}内的与多少个@Test,就循环执行多少次)。


1、配置文件结构(较详细):

<?xml version="1.0" encoding="UTF-8"?>
<!--添加dtd约束文件,标签自动提示-->
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite>
     <suite-files>
          <suite-file path=""></suite-file>
     </suite-files>
     <parameter name="" value=""></parameter>
     <method-selectors>
          <method-selector>
               <selector-calss name=""></selector-calss>
          </mehod-selector>
     </method-selectors>
     <test name="">
          <parameter name="" value=""><parameter>
          <groups>
               <define name="">
                    <include name=""/>
                    <exclude name=""/>
               </define>
               <run>
                    <include name=""/>
                    <exclude name=""/>
               </run>
          </groups>
          <classes>
               <class name="">
                    <mehods>
                         <parameter name="" value=""></parameter>
                         <include name=""></include>
                         <exclude name=""></exclude>
                    </methods>
               </class>
               <class></class>
          </classes>
          <packages>
               <package name="">
                    <include name=""></include>
                    <exclude name=""></exclude>
               </package>
          </packages>
          <listeners>
               <listener class-name=""/>
          </listenters>
     </test>
     <test></test>
</suite>



说明:一个xml文件只能有一个<suite>, 是一个xml文件的根级

<suite> 由 <test> 和 <parameters> 组成

标签属性说明:

属性 说明 使用方法 参数值
name 必选项,的名字,将出现在reports里 name="XXX" suite名字
junit 是否执行Junit模式(识别setup()等) junit="true" true和false,默认false
verbose 控制台输出的详细内容等级,0-10级(0无,10最详细) verbose="5" 0到10
parallel 是否在不同的线程并行进行测试,要与thread-count配套使用 parallel="mehods" 详见表格下内容,默认false
parent-module 和Guice框架有关,只运行一次,创建一个parent injector给所有guice injectors    
guice-stage 和Guice框架有关 guice-stage="DEVELOPMENT" DEVELOPMENT,PRODUCTION,TOOL,默认"DEVELOPMENT"
configfailurepolicy 测试失败后是再次执行还是跳过,值skip和continue configfailurepolicy="skip" skip、continue,默认skip
thread-count 与parallel配套使用,线程池的大小,决定并行线程数量 thread-count="10" 整数,默认5
annotations 获取注解,值为javadoc时,使用JavaDoc的注释;否则用JDK5注释 annotations="javadoc" javadoc
time-out 设置parallel时,终止执行单元之前的等待时间(毫秒) time-out="10000" 整数,单位毫秒
skipfailedinvocationcounts 是否跳过失败的调用 skipfailedinvocationcounts="true" true和false,默认false
data-provider-thread-count 并发时data-provider的线程池数量 data-provider-thread-count="5" 整数
object-factory 一个实现IObjectFactory接口的类,实例化测试对象 object-factory="classname" 类名
allow-return-values 是否允许返回函数值 all-return-values="true" true和false
preserve-order 是否按照排序执行 preserve-order="true" true和false,默认true
group-by-instances 按照实例分组 group-by-instances="true" true和false,默认false

parallel 属性详细说明

该参数的值falsemethodstestsclassesinstances。默认false

parallel 必须和 thread-count 配套使用,否则相当于无效参数,thread-count 决定了并行测试时开启的线程数量

parallel="mehods" TestNG将并行执行所有的测试方法在不同的线程里

parallel="tests" TestNG将并行执行在同一个<test>下的所有方法在不同线程里

parallel="classes" TestNG将并行执行在相同<class>下的方法在不同线程里

parallel="instances" TestNG将并行执行相同实例下的所有方法在不同的县城里

parent-module 和guice-stage 和 Guice 框架有关,testNG 6对 Guice 框架提供了支持,我没用过这个框架,所以这两个参数没看懂╮(╯▽╰)╭


说明:引入外部的xml文件(地址由path参数决定,path必填项),将引入的xml与当前的xml文件一起使用

声明方法:

Copy
suite-files>

   <suite-file path="/path/suitefile1"></suite-file>

</suite-files>


说明:一个<suite>下可以有多个<test>,可以通过<suite>parallel="tests"来进行并行测试,必须和thread-count配套使用,否则是无效参数

<test><parameters>、<groups>、<classes>三部分组成

标签属性说明:

参数 说明 使用方法 参数值
name test的名字,将出现在报告里 name="testname" test的名字
junit 是否按照Junit模式运行 junit="true" true和false,默认false
verbose 控制台输出的详细内容等级,0-10级(0无,10最详细),不在报告显示 verbose="5" 0到10
parallel 是否在不同的线程并行进行测试,要与thread-count配套使用 parallel="mehods" 与suite的parallel一致,默认false
thread-count 与parallel配套使用,线程池的大小,决定并行线程数量 thread-count="10" 整数,默认5
annotations 获取注解,值为javadoc时,使用JavaDoc的注释;否则用JDK5注释 annotations="javadoc" javadoc
time-out 设置parallel时,终止执行单元之前的等待时间(毫秒) time-out="10000" 整数,单位毫秒
enabled 标记是否执行这个test enabled="true" true和false,默认true
skipfailedinvocationcounts 是否跳过失败的调用 skipfailedinvocationcounts="true" true和false,默认false
preserve-order 是否按照排序执行,如果是true,将按照xml文件中的顺序去执行 preserve-order="true" true和false,默认true
allow-return-values 是否允许返回函数值 all-return-values="true" true和false,默认false


说明:提供测试数据,有name和value两个参数

声明方法:<parameter name = "parameter_name" value = "parameter_value "/>

testng.xml 文件中的<parameter>可以声明在<suite>或者<test>级别,在<test>下的<parameter>会覆盖在<suite>下声明的同名变量


说明:要运行的组,可以自定义一个组,可以包括要执行的,还排除要执行的方法。必须和<classes>配套使用,从下面的类中找到对应名字的方法

<groups> 由<difine> 和 <run>、<dependencies> 三部分组成。

<diffine>可以将 group 组成一个新组,包括要执行和不执行的大组;

<run>要执行的方法;

<dependencies> 指定了某 group 需要依赖的 group(比如下面的例子,group1 需要依赖 group2 和 group3 先执行)。

声明方法:

<groups>
            
    <define name ="all">
        <include name ="testgroup1"/>
    </define>

    <run>
        <include name ="testmethod1"/>
        <exclude name="testmethod2"/>
    </run>

    <dependencies>
        <group name ="group1" depends-on="goup2 group3"/>
    </dependencies>

</groups>


说明:方法选择器,要执行的方法写在这里,参数有name和priority。

注释:

1.<classes>下必须写要执行的<class>,否则不会执行任何内容,如果填写了 class 没有写 methods,会按照填写的 class 的下的注释 @Test 去执行所有的方法

2.<classes>下的<methods>如果填写了<include>,那只会执行所填写的方法,没有填写的方法不会去执行

声明方法:

<classes>

   <class name="要执行的class名">
       <methods>
           <include name ="要执行的方法名"></include>
       </methods>
   </class> 

</classes>



(1)创建测试类:PatamterTest.java

package com.ggf.testng.paramter;

import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

/**
 * @Description: testNG的参数化配置,通过xml文件进行方法的赋值操作
 * @Author: ggf
 * @Date: 2019/12/29
 */
public class PatamterTest {
    @Test
    @Parameters({"name","age"})
    public void showInfo(String name, int age) {
        System.out.println("name="+ name + " age=" + age);
    }

}

(2)创建配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="paramterTest">
    <test name="transfer">
        <classes>
            <class name="com.ggf.testng.paramter.PatamterTest"/>
            <parameter name="name" value="张三"/>
            <parameter name="age" value="11"/>
        </classes>
    </test>
    
</suite>

(3)运行结果:

[TestNG] Running:
  D:workspace	estwork	estNGDemosrcmain
esourcesparamter.xml

name=张三 age=11

===============================================
paramterTest
Total tests run: 1, Failures: 0, Skips: 0
===============================================


示例:

package com.ggf.testng.paramter;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description:  主要是对DataProvider注解的学习,通过这个注解的标识,来给测试类进行赋值。
 * @Author: ggf
 * @Date: 2019/12/29
 * 首先定义一个数据源的方法,通过@DataProvider注解来标识。
 * 然后定义一个测试方法,通过@Test(dataProvider="")属性来获取数据
 */
public class DataProviderTest {
    /**
     * 数据源,是方法提供数据,返回必须是一个二维数组
     * @DataProvider(name = "data") 通过该注解来标识这个为数据源,name为数据源的名称。
     * @return 返回一个二维数组
     */
    @DataProvider(name = "data")
    public Object[][] providerData() {
        Object[][] data = new Object[][] {
                {"zhangsan",12},
                {"lisi",22},
                {"wangwu",32}
        };

        return data;
    }

    /**
     * 通过dataProvider来获取数据,执行的次数会根据数据源提供数据的数量
     * 例如上面的二维数组长度为3,则该方法会执行三次。
     * @param name
     * @param age
     */
    @Test(dataProvider = "data")
    public void testDataProvider(String name, int age) {
        System.out.println("name=" + name + " age=" + age);
    }


}

运行结果:

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml
  
name=zhangsan age=12

name=lisi age=22

name=wangwu age=32

===============================================
Default Suite
Total tests run: 3, Failures: 0, Skips: 0
===============================================



invocationCount:线程调用的次数,默认1次。

threadPoolSize:线程池大小,和 invocationCount 一起使用,如果没有定义 invocationCount ,定义了threadPoolSize,是没有效果的。

@Test(invocationCount = 10,threadPoolSize = 3)

invocationCount 默认这个属性的值是 1, 即只会执行一次,当从新赋值时,该方法就会执行多次。

这里就是,定义了三个线程,来执行这个方法10次。

示例:

package com.course.testng.multiThread;

import org.testng.annotations.Test;

public class MultiThreadOnAnnotion {

    @Test(invocationCount = 10,threadPoolSize = 3)
    public void test(){
        System.out.println(1);
        System.out.printf("Thread Id : %s%n",Thread.currentThread().getId());
    }

}

运行结果:

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml
  
1
1
1
Thread Id : 12
Thread Id : 11
1
Thread Id : 11
Thread Id : 13
1
Thread Id : 12
1
Thread Id : 12
1
Thread Id : 11
1
Thread Id : 12
1
Thread Id : 12
1
Thread Id : 13

===============================================
Default Suite
Total tests run: 10, Failures: 0, Skips: 0
===============================================

从输出结果可以看出,一共有三条线程在执行,一共执行了10次(输出了10个1)


(1)创建测试类:MultiThreadOnXml.java

package com.ggf.testng.multithread;

import org.testng.annotations.Test;

/**
 * @Description: 使用配置文件来实现testng的多线程
 * @Author: ggf
 * @Date: 2020/02/01
 */
public class MultiThreadOnXml {
    @Test
    public void test1() {
        System.out.printf("Thread id: %s%n", Thread.currentThread().getId());
    }

    @Test
    public void test2() {
        System.out.printf("Thread id: %s%n", Thread.currentThread().getId());
    }

    @Test
    public void test3() {
        System.out.printf("Thread id: %s%n", Thread.currentThread().getId());
    }
}

(2)配置文件编写

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="thread" parallel="methods" thread-count="3">
    <!--
    tests级别:不同的test tag下的用例可以在不同的线程下执行
            相同的test tag下的用例只能在同一个线程中去执行
    classs级别:相同的class tag 下的用例在同一个线程中执行
                不同的class tag 下的用例可以在不同的线程中执行
    methods级别:所有用例都可以在不同的线程下去执行

    thread-count:代表了最大并发线程数

    xml文件配置这种方式不能指定线程池,只有方法上才可以指定线程池
    -->
    <test name="test1">
        <classes>
            <class name="com.ggf.testng.multithread.MultiThreadOnXml"/>
        </classes>
    </test>
</suite>

(3) 运行结果

[TestNG] Running:
  D:workspace	estwork	estNGDemosrcmain
esourcesmultithread.xml

Thread id: 11
Thread id: 13
Thread id: 12

===============================================
thread
Total tests run: 3, Failures: 0, Skips: 0
===============================================

输出结果可以看出,有三条线程分别执行了不同的方法。

转自:https://www.cnblogs.com/tester-ggf/p/12249496.html

参考资料:

博客:

https://www.cnblogs.com/aland-1415/p/10475957.html

https://www.cnblogs.com/meitian/p/5221202.html

视频教程:

https://coding.imooc.com/class/204.html

TestNG 是一个测试框架,其灵感来自 JUnit 和 NUnit,但同时引入了一些新的功能,使其功能更强大,使用更方便。

TestNG 设计涵盖所有类型的测试:单元,功能,端到端,集成等,它需要 JDK5 或更高的 JDK 版本。

详细使用说明请参考官方链接:https://testng.org/doc/index.html

在 maven 中引入依赖:

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>6.10</version>
</dependency>

简单示例:

(1)被测试 HelloWorld 类

package study.testng;

public class HelloWorld {

    public String hello(){
        return "hello world !";
    }
}

(2)测试类 TestHelloWorld 类

package study.testng;

import org.testng.Assert;
import org.testng.annotations.Test;

public class TestHelloWorld {

    //测试返回结果不为空
    @Test
    public void tester1(){
        HelloWorld hello = new HelloWorld();
        String helloworld = hello.hello();

        Assert.assertNotNull(helloworld);
    }
    
    //测试返回结果为”hello world !“字符串
    @Test
    public void tester2(){
        HelloWorld hello = new HelloWorld();
        String helloworld = hello.hello();
        System.out.println(helloworld);

        Assert.assertEquals(helloworld, "hello world !");
    }
}

(3)测试结果

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml

hello world !

===============================================
Default Suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================


凡是在类方法中添加了 @Test 注解的就是我们需要测试的方法


默认是 true , 如果设置为 false ,则在运行时不会执行这个测试方法;

示例:

package com.ggf.testng.annotation;

import org.testng.annotations.Test;

/**
 * @Description: 忽略测试,可以通过@Test的注解的enable属性来配置是否执行用例方法
 * enable默认值为 true,需要设置为false才会跳过这个测试用例
 * @Author: ggf
 * @Date: 2019/12/29
 */
public class IgnoreTest {
    @Test
    public void ignore1() {
        System.out.println("ignore1 run...");
    }

    @Test(enabled = false)
    public void ignore2() {
        System.out.println("ignore2 run ...");
    }

    @Test
    public void ignore3() {
        System.out.println("ignore3 run ...");
    }
}

运行结果:

 
[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml
ignore1 run...
ignore3 run ...
===============================================
Default Suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================


@Test(expectedExceptions = ClassName.class)
如果 ClassName 类抛出了异常,测算测试通过,没有异常算测试不通过;

expectedExceptions的值也可以是一个数组:
@Test(expectedExceptions = {ClassName.class, ClassName2.class,... })

示例:

package com.ggf.testng.annotation;

import org.testng.annotations.Test;

/**
 * @Description:  异常测试
 * @Author: ggf
 * @Date: 2019/12/29
 *
 * 什么时候会用到异常测试??
 * 在我们期望结果为某一个异常的时候
 * 比如:我们传入了某些不合法的参数,程序抛出了异常
 * 也就是说我的期望结果就是这个异常。
 */
public class ExpectedException {
    /**
     * 运行时异常,我们期望返回一个运行时异常,这条用例才是正确的。
     */
    @Test(expectedExceptions = RuntimeException.class, enabled = false)
    public void runTimeExceptionFailed() {
        System.out.println("没有抛出异常,这条用例不通过!");
    }

    /**
     * 结果抛出了一个运行时异常,和我们的期望一致,测试通过。
     */
    @Test(expectedExceptions = RuntimeException.class)
    public void runTimeExceptionSuccess() {
        System.out.println("程序抛出了运行时异常,测试用例通过!");
        throw new RuntimeException();
    }

}

运行结果:

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml
程序抛出了运行时异常,测试用例通过!
===============================================
Default Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================


在被依赖的方法运行完成之后运行当前方法,如果依赖方法测试不通过,那么当前方法也不会继续运行了;依赖的方法可以有多个;

例:@Test(dependsOnMethods = { "methodName1" , “methodName2” })

示例:

 
package com.ggf.testng.annotation;

import org.testng.annotations.Test;

/**
 * @Description: 方法直接的依赖测试
 * @Author: ggf
 * @Date: 2019/12/29
 */
public class DependTest {
    @Test
    public void test1() {
        System.out.println("test1 run ...");
    }

    /**
     * test2运行时,需要依赖test1的运行
     * 如果test1运行失败,会直接忽略test2, test2就不会执行了。
     */
    @Test(dependsOnMethods = {"test1"})
    public void test2() {
        System.out.println("test2 run ...");
    }
}


  • 把在一个<test>标签内的中所有类方法再进行组,在运行时,一个组的方法会一起运行,然后再运行下一个组的方法;

  • 分组的最小维度为方法,当把带分组的@Test(groups = ”groupName”)注解对类使用时,这个测试类中的所有方法都属于这同一个组;

  • 一个方法也可以同时属于多个组,@Test(groups = {“groupName1”, “groupName2”}),那么每组运行时这个方法都会被执行一次;

  • 同一个组里的方法类,如果分别属于两个不同的测试用例(<test>)内,那么它们其实可以算两个组,它们会在每个测试用例分别运行,而不会合在一起运行;

示例:

package com.ggf.testng.groups;

import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;

import javax.sound.midi.Soundbank;

/**
 * @Description: 对测试用例方法进行分组,可以对一组中的数据进行初始化
 * @Author: ggf
 * @Date: 2019/12/29
 */
public class GroupsOnMethod {
    @BeforeGroups(groups = "server")
    public void beforeGroupsOnServer() {
        System.out.println("服务端组运行前执行的方法。。。");
    }

    @BeforeGroups(groups = "client")
    public void beforeGroupsOnClient() {
        System.out.println("客户端组运行前执行的方法。。。");
    }

    @Test(groups = "server")
    public void test1() {
        System.out.println("server test1 run ....");
    }

    @Test(groups = "server")
    public void test2() {
        System.out.println("server test2 run ....");
    }

    @Test(groups = "client")
    public void test3() {
        System.out.println("client test3 run ....");
    }

    @Test(groups = "client")
    public void test4() {
        System.out.println("client test4 run ....");
    }

    @AfterGroups(groups = "server")
    public void afterGroupsOnServer() {
        System.out.println("服务端组运行之后执行的方法。。。");
    }

    @AfterGroups(groups = "client")
    public void afterGroupsOnClient() {
        System.out.println("客户端组运行之后执行的方法。。。");
    }
}

运行结果:

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml
  
服务端组运行前执行的方法。。。
server test1 run ....
server test2 run ....
服务端组运行之后执行的方法。。。


客户端组运行前执行的方法。。。
client test3 run ....
client test4 run ....
客户端组运行之后执行的方法。。。

===============================================
Default Suite
Total tests run: 4, Failures: 0, Skips: 0
===============================================


@Test(timeOut = 3000) 设置超时时间,单位为毫秒。

示例:

package com.course.testng;

import org.testng.annotations.Test;

public class TimeOutTest {

    /**
     * 单位为毫秒值,3秒内没有响应,就证明失败了,反之成功
     * @throws InterruptedException
     */
    @Test(timeOut = 3000)
    public void testSuccess() throws InterruptedException {
        Thread.sleep(2000);
    }

    @Test(timeOut = 2000)
    public void testFailed() throws InterruptedException {
        Thread.sleep(3000);
    }
}

运行结果:

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml

org.testng.internal.thread.ThreadTimeoutException: Method com.course.testng.TimeOutTest.testFailed() didn't finish within the time-out 2000

===============================================
Default Suite
Total tests run: 2, Failures: 1, Skips: 0
===============================================


属性名 描述
alwaysRun 设置为 true 时,无论什么情况都会运行
dataProvider 数据提供者的名称
dataProviderClass 如果未指定,将在当前测试方法的类或其父类之一上查找数据提供者。 如果指定了此属性,则数据提供者方法在指定的类上必须是静态的。
dependsOnGroups 依赖的组列表
dependsOnMethods 依赖的方法列表
description 说明
enabled 默认为true,设置为 false 时失效
expectedExceptions 预期测试方法将引发的异常列表。 如果未引发任何异常或与该列表中的异常不同,则此测试将标记为失败。
groups 所属组
invocationCount 调用次数
invocationTimeOut 所有 invocationCount 的累积超时时间。 注意:如果未指定 nvocationCount,则将忽略此属性。
priority 此测试方法的优先级
successPercentage 该方法预期成功的百分比
singleThreaded 如果设置为 rue,则即使当前正在使用 parallel =“ methods” 运行测试,也保证该测试类上的所有方法都可以在同一线程中运行。 此属性只能在类级别使用,如果在方法级别使用,则将被忽略。
timeOut 超时时间
threadPoolSize 此方法的线程池的大小。 该方法将从 invocationCount 指定的多个线程中调用。 注意:如果未指定 invocationCount,则忽略此属性


注解 描述
@BeforeSuite 在该套件的所有测试都运行在注释的方法之前,仅运行一次(套件测试是一起运行的多个测试类)。
@AfterSuite 在该套件的所有测试都运行在注释方法之后,仅运行一次。
@BeforeClass 在调用当前类的第一个测试方法之前运行,注释方法仅运行一次。
@AfterClass 在调用当前类的第一个测试方法之后运行,注释方法仅运行一次。
@BeforeTest 注释的方法将在属于<test>标签内的类的所有测试方法运行之前运行。
@AfterTest 注释的方法将在属于<test>标签内的类的所有测试方法运行之后运行。
@BeforeGroups 配置方法将在之前运行组列表。 此方法保证在调用属于这些组中的任何一个的第一个测试方法之前不久运行。
@AfterGroups 此配置方法将在之后运行组列表。该方法保证在调用属于任何这些组的最后一个测试方法之后不久运行。
@BeforeMethod 注释方法将在每个测试方法之前运行。
@AfterMethod 注释方法将在每个测试方法之后运行。
@Parameters 描述如何将参数传递给@Test方法。
@DataProvider 标记一种方法来提供测试方法的数据。 注释方法必须返回一个Object [] [],其中每个Object []可以被分配给测试方法的参数列表。 要从该DataProvider接收数据的@Test方法需要使用与此注释名称相等的dataProvider名称。
@Factory 将一个方法标记为工厂,返回TestNG将被用作测试类的对象。 该方法必须返回Object []。
@Listeners 定义测试类上的侦听器。
@Test 将类或方法标记为测试的一部分。

示例:

测试类 TestConfig.java

package study.testng;

import org.testng.annotations.AfterGroups;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class TestConfig {

    @BeforeSuite
    public void beforeSuite() {
        System.out.println("测试套件(当前xml中<suite>标签)之前运行@BeforeSuite--------------------");
    }

    @AfterSuite
    public void afterSuite() {
        System.out.println("测试套件(当前xml中<suite>标签)之后运行@AfterSuite--------------------
");
    }

    @BeforeTest
    public void beforeTest() {
        System.out.println("测试用例(当前xml中<test>标签)之前运行@BeforeTest----------");
    }

    @AfterTest
    public void afterTest() {
        System.out.println("测试用例(当前xml中<test>标签)之后运行@AfterTest----------
");
    }
    
    @BeforeMethod
    public void beforeMethod() {
        System.out.println("当前类每个测试方法(@Test)之前运行@BeforeMethod");
    }
    
    @AfterMethod
    public void AfterMethod(){
        System.out.println("当前类每个测试方法(@Test)之后运行@AfterMethod");
    }
    
    @BeforeGroups(value="group1")
    public void beforeGroups(){
        System.out.println("配置组配group1之前运行@BeforeGroups..................");
    }
    @AfterGroups(value="group1")
    public void afterGroups(){
        System.out.println("配置组配group1之前运行@AfterGroups..................");
    }
    
    @Test
    public void test1(){
        System.out.println("runnig TestConfig.test1()");
    }
    
    @Test(groups = "group1")
    public void test2(){
        System.out.println("runnig TestConfig.test2()");
    }
    
    @Test(groups = "group1")
    public void test3(){
        System.out.println("runnig TestConfig.test3()");
    }
    
}

新建一个自定义 xml 配置文件 tester.xml (maven项目将该文件创建在 resource 目录下)

<?xml version="1.0" encoding="UTF-8"?>

<!-- @BeforeSuite -->
<suite name="tester">

    <!-- @BeforeTest -->
    <test name="case1">
      <classes>
        <class name="study.testng.TestConfig" />
        <class name="study.testng.TestHelloWorld" />
      </classes>
    </test>
    <!-- @AfterTest -->
    
    <!-- @BeforeTest -->
    <test name="case2">
      <classes>
        <class name="study.testng.TestConfig" />
      </classes>
    </test>
    <!-- @AfterTest -->

</suite>
<!-- @AfterSuite -->

运行结果:

【转】TestNG使用详解
一、testng 介绍
二、@Test注解及常用属性
三、testng常用注解
四、testng.xml 配置文件详解
五、testng 中方法参数传递
六、testng 多线程测试

从这个结果显示出注释的作用位置。其中 @BeforeGroups 和 @AfterGroups 的作用范围是可以跨类的,但类必须是在同一个测试用例(<test>标签)范围内;

这些标签的运行先后顺序可以总结为:

@BeforeSuite->@BeforeTest->@BeforeClass->{@BeforeMethod->@Test->@AfterMethod}->@AfterClass->@AfterTest->@AfterSuite(其中{}内的与多少个@Test,就循环执行多少次)。


1、配置文件结构(较详细):

<?xml version="1.0" encoding="UTF-8"?>
<!--添加dtd约束文件,标签自动提示-->
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite>
     <suite-files>
          <suite-file path=""></suite-file>
     </suite-files>
     <parameter name="" value=""></parameter>
     <method-selectors>
          <method-selector>
               <selector-calss name=""></selector-calss>
          </mehod-selector>
     </method-selectors>
     <test name="">
          <parameter name="" value=""><parameter>
          <groups>
               <define name="">
                    <include name=""/>
                    <exclude name=""/>
               </define>
               <run>
                    <include name=""/>
                    <exclude name=""/>
               </run>
          </groups>
          <classes>
               <class name="">
                    <mehods>
                         <parameter name="" value=""></parameter>
                         <include name=""></include>
                         <exclude name=""></exclude>
                    </methods>
               </class>
               <class></class>
          </classes>
          <packages>
               <package name="">
                    <include name=""></include>
                    <exclude name=""></exclude>
               </package>
          </packages>
          <listeners>
               <listener class-name=""/>
          </listenters>
     </test>
     <test></test>
</suite>



说明:一个xml文件只能有一个<suite>, 是一个xml文件的根级

<suite> 由 <test> 和 <parameters> 组成

标签属性说明:

属性 说明 使用方法 参数值
name 必选项,的名字,将出现在reports里 name="XXX" suite名字
junit 是否执行Junit模式(识别setup()等) junit="true" true和false,默认false
verbose 控制台输出的详细内容等级,0-10级(0无,10最详细) verbose="5" 0到10
parallel 是否在不同的线程并行进行测试,要与thread-count配套使用 parallel="mehods" 详见表格下内容,默认false
parent-module 和Guice框架有关,只运行一次,创建一个parent injector给所有guice injectors    
guice-stage 和Guice框架有关 guice-stage="DEVELOPMENT" DEVELOPMENT,PRODUCTION,TOOL,默认"DEVELOPMENT"
configfailurepolicy 测试失败后是再次执行还是跳过,值skip和continue configfailurepolicy="skip" skip、continue,默认skip
thread-count 与parallel配套使用,线程池的大小,决定并行线程数量 thread-count="10" 整数,默认5
annotations 获取注解,值为javadoc时,使用JavaDoc的注释;否则用JDK5注释 annotations="javadoc" javadoc
time-out 设置parallel时,终止执行单元之前的等待时间(毫秒) time-out="10000" 整数,单位毫秒
skipfailedinvocationcounts 是否跳过失败的调用 skipfailedinvocationcounts="true" true和false,默认false
data-provider-thread-count 并发时data-provider的线程池数量 data-provider-thread-count="5" 整数
object-factory 一个实现IObjectFactory接口的类,实例化测试对象 object-factory="classname" 类名
allow-return-values 是否允许返回函数值 all-return-values="true" true和false
preserve-order 是否按照排序执行 preserve-order="true" true和false,默认true
group-by-instances 按照实例分组 group-by-instances="true" true和false,默认false

parallel 属性详细说明

该参数的值falsemethodstestsclassesinstances。默认false

parallel 必须和 thread-count 配套使用,否则相当于无效参数,thread-count 决定了并行测试时开启的线程数量

parallel="mehods" TestNG将并行执行所有的测试方法在不同的线程里

parallel="tests" TestNG将并行执行在同一个<test>下的所有方法在不同线程里

parallel="classes" TestNG将并行执行在相同<class>下的方法在不同线程里

parallel="instances" TestNG将并行执行相同实例下的所有方法在不同的县城里

parent-module 和guice-stage 和 Guice 框架有关,testNG 6对 Guice 框架提供了支持,我没用过这个框架,所以这两个参数没看懂╮(╯▽╰)╭


说明:引入外部的xml文件(地址由path参数决定,path必填项),将引入的xml与当前的xml文件一起使用

声明方法:

Copy
suite-files>

   <suite-file path="/path/suitefile1"></suite-file>

</suite-files>


说明:一个<suite>下可以有多个<test>,可以通过<suite>parallel="tests"来进行并行测试,必须和thread-count配套使用,否则是无效参数

<test><parameters>、<groups>、<classes>三部分组成

标签属性说明:

参数 说明 使用方法 参数值
name test的名字,将出现在报告里 name="testname" test的名字
junit 是否按照Junit模式运行 junit="true" true和false,默认false
verbose 控制台输出的详细内容等级,0-10级(0无,10最详细),不在报告显示 verbose="5" 0到10
parallel 是否在不同的线程并行进行测试,要与thread-count配套使用 parallel="mehods" 与suite的parallel一致,默认false
thread-count 与parallel配套使用,线程池的大小,决定并行线程数量 thread-count="10" 整数,默认5
annotations 获取注解,值为javadoc时,使用JavaDoc的注释;否则用JDK5注释 annotations="javadoc" javadoc
time-out 设置parallel时,终止执行单元之前的等待时间(毫秒) time-out="10000" 整数,单位毫秒
enabled 标记是否执行这个test enabled="true" true和false,默认true
skipfailedinvocationcounts 是否跳过失败的调用 skipfailedinvocationcounts="true" true和false,默认false
preserve-order 是否按照排序执行,如果是true,将按照xml文件中的顺序去执行 preserve-order="true" true和false,默认true
allow-return-values 是否允许返回函数值 all-return-values="true" true和false,默认false


说明:提供测试数据,有name和value两个参数

声明方法:<parameter name = "parameter_name" value = "parameter_value "/>

testng.xml 文件中的<parameter>可以声明在<suite>或者<test>级别,在<test>下的<parameter>会覆盖在<suite>下声明的同名变量


说明:要运行的组,可以自定义一个组,可以包括要执行的,还排除要执行的方法。必须和<classes>配套使用,从下面的类中找到对应名字的方法

<groups> 由<difine> 和 <run>、<dependencies> 三部分组成。

<diffine>可以将 group 组成一个新组,包括要执行和不执行的大组;

<run>要执行的方法;

<dependencies> 指定了某 group 需要依赖的 group(比如下面的例子,group1 需要依赖 group2 和 group3 先执行)。

声明方法:

<groups>
            
    <define name ="all">
        <include name ="testgroup1"/>
    </define>

    <run>
        <include name ="testmethod1"/>
        <exclude name="testmethod2"/>
    </run>

    <dependencies>
        <group name ="group1" depends-on="goup2 group3"/>
    </dependencies>

</groups>


说明:方法选择器,要执行的方法写在这里,参数有name和priority。

注释:

1.<classes>下必须写要执行的<class>,否则不会执行任何内容,如果填写了 class 没有写 methods,会按照填写的 class 的下的注释 @Test 去执行所有的方法

2.<classes>下的<methods>如果填写了<include>,那只会执行所填写的方法,没有填写的方法不会去执行

声明方法:

<classes>

   <class name="要执行的class名">
       <methods>
           <include name ="要执行的方法名"></include>
       </methods>
   </class> 

</classes>



(1)创建测试类:PatamterTest.java

package com.ggf.testng.paramter;

import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

/**
 * @Description: testNG的参数化配置,通过xml文件进行方法的赋值操作
 * @Author: ggf
 * @Date: 2019/12/29
 */
public class PatamterTest {
    @Test
    @Parameters({"name","age"})
    public void showInfo(String name, int age) {
        System.out.println("name="+ name + " age=" + age);
    }

}

(2)创建配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="paramterTest">
    <test name="transfer">
        <classes>
            <class name="com.ggf.testng.paramter.PatamterTest"/>
            <parameter name="name" value="张三"/>
            <parameter name="age" value="11"/>
        </classes>
    </test>
    
</suite>

(3)运行结果:

[TestNG] Running:
  D:workspace	estwork	estNGDemosrcmain
esourcesparamter.xml

name=张三 age=11

===============================================
paramterTest
Total tests run: 1, Failures: 0, Skips: 0
===============================================


示例:

package com.ggf.testng.paramter;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description:  主要是对DataProvider注解的学习,通过这个注解的标识,来给测试类进行赋值。
 * @Author: ggf
 * @Date: 2019/12/29
 * 首先定义一个数据源的方法,通过@DataProvider注解来标识。
 * 然后定义一个测试方法,通过@Test(dataProvider="")属性来获取数据
 */
public class DataProviderTest {
    /**
     * 数据源,是方法提供数据,返回必须是一个二维数组
     * @DataProvider(name = "data") 通过该注解来标识这个为数据源,name为数据源的名称。
     * @return 返回一个二维数组
     */
    @DataProvider(name = "data")
    public Object[][] providerData() {
        Object[][] data = new Object[][] {
                {"zhangsan",12},
                {"lisi",22},
                {"wangwu",32}
        };

        return data;
    }

    /**
     * 通过dataProvider来获取数据,执行的次数会根据数据源提供数据的数量
     * 例如上面的二维数组长度为3,则该方法会执行三次。
     * @param name
     * @param age
     */
    @Test(dataProvider = "data")
    public void testDataProvider(String name, int age) {
        System.out.println("name=" + name + " age=" + age);
    }


}

运行结果:

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml
  
name=zhangsan age=12

name=lisi age=22

name=wangwu age=32

===============================================
Default Suite
Total tests run: 3, Failures: 0, Skips: 0
===============================================



invocationCount:线程调用的次数,默认1次。

threadPoolSize:线程池大小,和 invocationCount 一起使用,如果没有定义 invocationCount ,定义了threadPoolSize,是没有效果的。

@Test(invocationCount = 10,threadPoolSize = 3)

invocationCount 默认这个属性的值是 1, 即只会执行一次,当从新赋值时,该方法就会执行多次。

这里就是,定义了三个线程,来执行这个方法10次。

示例:

package com.course.testng.multiThread;

import org.testng.annotations.Test;

public class MultiThreadOnAnnotion {

    @Test(invocationCount = 10,threadPoolSize = 3)
    public void test(){
        System.out.println(1);
        System.out.printf("Thread Id : %s%n",Thread.currentThread().getId());
    }

}

运行结果:

[TestNG] Running:
  C:UsersAdministrator.IntelliJIdea2019.2system	emp-testng-customsuite.xml
  
1
1
1
Thread Id : 12
Thread Id : 11
1
Thread Id : 11
Thread Id : 13
1
Thread Id : 12
1
Thread Id : 12
1
Thread Id : 11
1
Thread Id : 12
1
Thread Id : 12
1
Thread Id : 13

===============================================
Default Suite
Total tests run: 10, Failures: 0, Skips: 0
===============================================

从输出结果可以看出,一共有三条线程在执行,一共执行了10次(输出了10个1)


(1)创建测试类:MultiThreadOnXml.java

package com.ggf.testng.multithread;

import org.testng.annotations.Test;

/**
 * @Description: 使用配置文件来实现testng的多线程
 * @Author: ggf
 * @Date: 2020/02/01
 */
public class MultiThreadOnXml {
    @Test
    public void test1() {
        System.out.printf("Thread id: %s%n", Thread.currentThread().getId());
    }

    @Test
    public void test2() {
        System.out.printf("Thread id: %s%n", Thread.currentThread().getId());
    }

    @Test
    public void test3() {
        System.out.printf("Thread id: %s%n", Thread.currentThread().getId());
    }
}

(2)配置文件编写

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="thread" parallel="methods" thread-count="3">
    <!--
    tests级别:不同的test tag下的用例可以在不同的线程下执行
            相同的test tag下的用例只能在同一个线程中去执行
    classs级别:相同的class tag 下的用例在同一个线程中执行
                不同的class tag 下的用例可以在不同的线程中执行
    methods级别:所有用例都可以在不同的线程下去执行

    thread-count:代表了最大并发线程数

    xml文件配置这种方式不能指定线程池,只有方法上才可以指定线程池
    -->
    <test name="test1">
        <classes>
            <class name="com.ggf.testng.multithread.MultiThreadOnXml"/>
        </classes>
    </test>
</suite>

(3) 运行结果

[TestNG] Running:
  D:workspace	estwork	estNGDemosrcmain
esourcesmultithread.xml

Thread id: 11
Thread id: 13
Thread id: 12

===============================================
thread
Total tests run: 3, Failures: 0, Skips: 0
===============================================

输出结果可以看出,有三条线程分别执行了不同的方法。

转自:https://www.cnblogs.com/tester-ggf/p/12249496.html

参考资料:

博客:

https://www.cnblogs.com/aland-1415/p/10475957.html

https://www.cnblogs.com/meitian/p/5221202.html

视频教程:

https://coding.imooc.com/class/204.html