利用半天时间入门testNG

TestNG使用分享

testNG是一个java测试框架,是Junit和Nunit的灵感结合体,具体介绍找度娘吧。
这篇文章只当是一篇入门(能够从认识到熟练使用的过程)教程吧,说是教程我的内心是拒绝的,毕竟不才,不敢教什么,全当是一次学习分享。

一、testNG安装

我的环境用的是win10、eclipse(201812新版本)、jdk9、testNG6.14.2。
这里只简单说明eclipse里安装testng.

在eclipse中选择help-Install new software

安装成功以后,可以新建一个Java项目进行测试
在这里插入图片描述

新建一个测试类
在这里插入图片描述

右键运行-AS-testNG.
如果运行成功就表示安装成功了,已经成功使用了,如果运行失败,可以发到评论里或者自己看异常排查一下。

二、用例执行方式

1.单个测试类执行,直接点击类右键RUN AS-testNG
2.xml配置方式执行,新增一个xml文件,随便叫什么名字都可以叫a.xml,b.xml都可以,我这里文件叫testng.xml,按照以下配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
       <test name="test1">
              <classes>
                     <class name="lxh.test.NewTest1">
                           <methods>
                                  <include name="f2"></include>
                                  <include name="f1"></include>
                           </methods>
                     </class>
              </classes>
       </test>
</suite>

include标签可以控制方法的执行顺序,以上配置f2函数会先执行,f1函数会后执行

三、testNG测试类别

1.异常测试
测试是否抛出指定异常,测试异常信息msg是否符合预期

  @Test(expectedExceptions=NullPointerException.class,expectedExceptionsMessageRegExp="出现错误")
  public void f3() {
         System.out.println("第三个方法");
         throw new NullPointerException("出现错误");
  }

2.分组测试
可以根据业务类型或系统模块进行测试分组,如:系统函数测试组groupSysFun,业务逻辑函数测试组groupBusFun,指定测试方法或测试类划入哪个组,再进行分组测试。
使用groups说明当前函数/类归于哪些分组,“gpSys”为组名,一个函数/类可以归于多个分组里面。

  //使用groups参数说明当前函数归于哪些分组
  //“gpSys”为组名,一个函数可以归于多个分组里面
  @Test(groups= {"gpSys"})
  public void f4() {
         System.out.println("gpSys-分组测试01");
  }
 
  @Test(groups= {"gpSys"})
  public void f5() {
         System.out.println("gpSys-分组测试02");
  }
 
  @Test(groups= {"gpBus"})
  public void f6() {
         System.out.println("gpBus-分组测试03");
  }
 

另一个类里面也有一个函数可以和前面的类放在同一个分组内,同时也可以归于多个分组

public class NewTest2 {
       
       @Test(groups= {"gpSys","gpBus"})
       public void f1() {
              System.out.println("gpSys-分组测试03");
       }
       
       @Test
       public void f2() {
              System.out.println("普通测试");
       }
}

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
       <test name="test1">
              <!-- <classes>
                     <class name="lxh.test.NewTest1">
                           <methods>
                                  <include name="f2"></include>
                                  <include name="f1"></include>
                                  <include name="f3"></include>
                           </methods>
                     </class>
              </classes> -->
              <groups><!-- 这里要注意在进行分组测试的时候,必须先定义groups标签,再引入class -->
                     <run>
                           <include name="gpSys"></include>
                           <include name="gpBus"></include>
                     </run>
              </groups>
              <classes><!-- 这里要注意class的顺序,执行测试的时候会按照这个顺序去执行 -->
                     <class name="lxh.test.NewTest2"></class>
                     <class name="lxh.test.NewTest1"></class>
              </classes>
       </test>
</suite>

测试结果:

在这里插入图片描述类分组测试

如果在类上加分组的话,那么类中的所有方法都属于这个类的所属分组中,在执行类分组测试时,将会执行类中的所有方法。以下例子中test2虽然添加了一个方法分组,但是同样也归属于class分组内。

@Test(groups= {"class-group-sys"})
public class GroupTestClassGP {
       
       /**
        * 当执行“class-group-sys”分组测试时,GroupTestClassGP类中的所有函数都会包含在这个分组内执行测试
        */
       public void test1() {
              System.out.println("class-group-sys:1");
       }
       
       /**
        * 这里test2是包含在“class-group-sys”分组内的,如果执行分组“class-group-sys”测试,test2()也会被执行
        */
       @Test(groups= {"method-group-sys"})
       public void test2() {
              System.out.println("method-group-sys:1");
       }
}

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
       <test name="test1">
              <groups><!-- 这里要注意在进行分组测试的时候,必须先定义groups标签,再引入class -->
                     <run>
                           <include name="class-group-sys"></include>
                     </run>
              </groups>
              <classes><!-- 这里要注意class的顺序,执行测试的时候会按照这个顺序去执行 -->
                     <class name="lxh.test.groups.GroupTestClassGP"></class>
              </classes>
       </test>
</suite>

执行结果:
在这里插入图片描述
exclude排除执行
当在进行自动化测试时,因为很多情况会需要批处理测试用例,如果在用例中有一些是不需要执行的,可以用exclude去排除这些不需要执行的用例。在testng.xml中可以使用exclude标签进行定义:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
       <test name="test1">
              <groups><!-- 这里要注意在进行分组测试的时候,必须先定义groups标签,再引入class -->
                     <run>
                           <include name="class-group-sys"></include>
                           <!-- exclude 定义了排除项,说明这个测试任务中排除“method-group-sys”分组,不执行 -->
                           <exclude name="method-group-sys"></exclude>
                     </run>
              </groups>
              <classes><!-- 这里要注意class的顺序,执行测试的时候会按照这个顺序去执行 -->
                     <class name="lxh.test.groups.GroupTestClassGP"></class>
              </classes>
       </test>
</suite>

分组测试资源初始化or关闭or销毁资源时,使用BeforeGroups和AfterGroups
beforeGroups在这个分组执行测试之前执行一次,AfterGroups在这个分组测试执行完毕之后执行一次

public class GroupTestClassGP2 {
       
       @BeforeGroups(groups= {"method-group-sys"})
       public void initGroupResource() {
              System.out.println("分组测试method-group-sys:初始化成功!");
       }
       
       @AfterGroups(groups= {"method-group-sys"})
       public void completedGroup() {
              System.out.println("分组测试method-group-sys:执行完毕!");
       }
       
       @Test(groups= {"method-group-sys","method-group-bus"})
       public void test1() {
              System.out.println("method:test1");
       }
       
       @Test(groups= {"method-group-sys"})
       public void test2() {
              System.out.println("method:test2");
       }
}

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
       <test name="test1">
              <groups><!-- 这里要注意在进行分组测试的时候,必须先定义groups标签,再引入class -->
                     <run>
                           <include name="method-group-sys"></include>
                     </run>
              </groups>
              <classes><!-- 这里要注意class的顺序,执行测试的时候会按照这个顺序去执行 -->
                     <class name="lxh.test.groups.GroupTestClassGP2"></class>
              </classes>
       </test>
</suite>

执行结果:
在这里插入图片描述

从执行结果可以看出来before和测试函数及after的执行顺序。

BeforeClass和AfterClass的使用,如果在分组测试的时候,需要在用例类方法执行之前或者执行后去增加一些操作,比如初始化一些公用资源和关闭资源的时候,可以使用这两个注解,注意一点就是这两个注解如果不传递groups参数的话,执行测试的时候是不执行注解方法的。

public class GroupTestClassGP2 {
       
       @BeforeClass(groups= {"method-group-sys"})
       public void initClassGP2() {
              System.out.println(GroupTestClassGP2.class+"初始化成功!");
       }
       
       @AfterClass(groups= {"method-group-sys"})
       public void completedClassGP2() {
              System.out.println(GroupTestClassGP2.class+"执行完毕!");
       }
       
       @BeforeGroups(groups= {"method-group-sys"})
       public void initGroupResource() {
              System.out.println("分组测试method-group-sys:初始化成功!");
       }
       
       @AfterGroups(groups= {"method-group-sys"})
       public void completedGroup() {
              System.out.println("分组测试method-group-sys:执行完毕!");
       }
       
       @Test(groups= {"method-group-sys","method-group-bus"})
       public void test1() {
              System.out.println("method:test1");
       }
       
       @Test(groups= {"method-group-sys"})
       public void test2() {
              System.out.println("method:test2");
       }
}

另一个类

public class GroupTestClassGP3 {
       
       @BeforeClass(groups= {"method-group-sys"})
       public void initClassGP3() {
              System.out.println(GroupTestClassGP3.class+"初始化完成!");
       }
       
       @Test(groups= {"method-group-sys","method-group-bus"})
       public void gP3test() {
              System.out.println("method:gP3test");
       }
       
       @AfterClass(groups= {"method-group-sys"})
       public void completedClassGP2() {
              System.out.println(GroupTestClassGP3.class+"执行完毕!");
       }
}

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
       <test name="test1">
              <groups><!-- 这里要注意在进行分组测试的时候,必须先定义groups标签,再引入class -->
                     <run>
                           <include name="method-group-sys"></include>
                     </run>
              </groups>
              <classes><!-- 这里要注意class的顺序,执行测试的时候会按照这个顺序去执行 -->
                     <class name="lxh.test.groups.GroupTestClassGP2"></class>
                     <class name="lxh.test.groups.GroupTestClassGP3"></class>
              </classes>
       </test>
</suite>

执行结果:
在这里插入图片描述
从结果可以看出来各个注解的执行顺序;以上例子中的顺序是这样的:
GroupTestClassGP2.beforeClass–>beforeGroups–>GroupTestClassGP2.test1–>GroupTestClassGP2.test2–>GroupTestClassGP2.afterClass–>GroupTestClassGP3.beforeClass–>GroupTestClassGP3.gp3Test–>afterGroups–>GroupTestClassGP3.afterClass
实际上这里面还有两个步骤,就是类初始化,执行构造函数的过程,执行过程应该是这样的
GroupTestClassGP2.无参构造函数–GroupTestClassGP2.beforeClass–>beforeGroups–>GroupTestClassGP2.test1–>GroupTestClassGP2.test2–>GroupTestClassGP2.afterClass–>GroupTestClassGP3.无参构造函数–>GroupTestClassGP3.beforeClass–>GroupTestClassGP3.gp3Test–>afterGroups–>GroupTestClassGP3.afterClass
这个测试结果也能看出来testng批量测试的时候测试类的执行顺序(testng.xml里面的class顺序);还有一个知识点是如果多个分组同用一个beforeGroups和afterGroups或者分别定义两个beforeGroups和一个afterGroups以及分别定义一个beforeGroups和两个afterGroups,这些场景的执行顺序和次数的问题,有时间的可以都试试。个人感觉实际使用的时候最好不要有上面这三种设计,会比较容易混乱。
testng还有很多before和after注解,有suite层的,class层的,test层的,group层的,method层的,这块的执行顺序我觉得还是挺有意思的,包括执行测试的队列分配(如果是自己去写的话会怎么设计),后面分析源码的时候可以再详细写写,希望有点惊喜。

3.参数测试(传参测试)
参数测试就是测试用例中需要使用到参数,那么执行测试的时候怎么给测试方法去传递这个参数。testng有两种方式传参,一种是在testng.xml文件里面去定义参数在用例方法上用Parameter注解去接收参数,一种是在测试类里面用注解DataProvider的方式传参。
第一种testng.xml定义参数使用方式是这样的

public class ParameterTest1 {
       @Test
       @Parameters({"param1"})
       public void test1(String param1) {
              System.out.println("获取到参数param1:"+param1);
       }
}

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
       <parameter name="param1" value="Anna"></parameter>
       <parameter name="param2" value="Test"></parameter>
       <parameter name="param3" value="Java"></parameter>
       <parameter name="param1" value="Linda"></parameter>
       <test name="test1">
              <classes>
                     <class name="lxh.test.parameter.ParameterTest1"></class>
              </classes>
       </test>
</suite>

这里要注意的是,如果一个参数在testng.xml里面定义了多次,如上面的param1定义了两次,执行的时候会取最后一个结果“Linda”(猜测这里用的是hashmap)
测试结果:
在这里插入图片描述

上面的parameter注解可以看出来能传递数组,所以如果要传递多个参数也是一样的,如果只有一个参数,可以不用数组的方式,那么多个参数的时候怎么使用注解呢,有两种方式,一种是在注解Test里面去调用parameters方法传参,但是这个方法已经deprecated了,所以推荐使用parameters注解

public class ParameterTest1 {
       @Test
       @Parameters({"param1"})
       public void test1(String param1) {
              System.out.println("获取到参数param1:"+param1);
       }
       
       @Test(parameters= {"param1","param2","param3"})
       public void test2(String param1,String param2,String param3) {
              System.out.println("test2:获取到参数param1"+param1+",参数param2"+param2+",参数param3"+param3);
       }
       
       @Test
       @Parameters({"param1","param2","param3"})
       public void test3(String param1,String param2,String param3) {
              System.out.println("test3:获取到参数param1"+param1+",参数param2"+param2+",参数param3"+param3);
       }
}

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
       <parameter name="param1" value="Anna"></parameter>
       <parameter name="param2" value="Test"></parameter>
       <parameter name="param3" value="Java"></parameter>
       <test name="test1">
              <classes>
                     <class name="lxh.test.parameter.ParameterTest1"></class>
              </classes>
       </test>
</suite>

运行结果:
在这里插入图片描述

如果在测试的时候用例有一些默认参数,在执行的时候不需要或者很少需要重新传递参数的话,可以直接使用可选参数注解optional,如果testng.xml中没有声明参数和值的话,执行用例时会直接使用这个optional的默认值

public class ParameterTest1 {
       @Test
       @Parameters("param1")
       public void test1(String param1) {
              System.out.println("获取到参数param1:"+param1);
       }
       
       
       @Test(parameters= {"param1","param2","param3"})
       public void test2(String param1,String param2,String param3) {
              System.out.println("test2:获取到参数param1"+param1+",参数param2"+param2+",参数param3"+param3);
       }
       
       @Test
       @Parameters({"param1","param2","param3"})
       public void test3(String param1,String param2,String param3) {
              System.out.println("test3:获取到参数param1"+param1+",参数param2"+param2+",参数param3"+param3);
       }
       
       @Test
       @Parameters("param4")
       public void test4(@Optional("Linda")String param1) {
              System.out.println("没有传递参数的时候会默认使用可选参数:"+param1);
       }
}

执行结果:
在这里插入图片描述
上面的执行结果和代码可以看出来test4中的param1和注解里面的参数名称不一样,实际上并不要求一样,只要顺序一样就可以,但是parameter注解里面的参数名称和testng.xml里面的paramter名称是需要一样的。
在testng的dtd里面可以看到,parameter在两个节点下都可以定义,一个是suite下面,一个是test下面,suite的作用范围比test要大,如果在分组测试的时候或者批量测试的时候,多个类多个测试计划里面都用到了同一个参数的话,比如数据库链接信息,可以写在suite里面,如果是需要单独赋值的,可以写在test里面,同时定义的话,test会覆盖suite。
上面的传参过程和执行结果可以看出来,testng.xml里面传参只能传递一次,如果需要动态传参反复测试的话或者是传递复杂参数的时候,testng.xml就实现不了了,就需要用到第二种传参方式dataprovider注解,使用方式就是DataProvider注解方法里面返回参数数组(注意这里必须要返回二维数组),在test测试里面用dataProvider指明使用的是哪个provider(这里是provider1)。

public class ParameterTest2 {
       
       @Test(dataProvider="provider1")
       public void test1(String param1,String param2) {
              System.out.println("获取到参数param1:"+param1+",NO."+param2);
       }
       
       @DataProvider(name="provider1")
       public Object[][] getParams() {
              return new String[][] {
                     {"China","1"},
                     {"Italy","2"}
              };
       }
}

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
       <test name="test1">
              <classes>
                     <class name="lxh.test.parameter.ParameterTest2"></class>
              </classes>
       </test>
</suite>

执行结果:
在这里插入图片描述
这里测试方法执行的次数是根据参数的行数来决定的,上面的例子里面提供了两行测试数据,所以执行了两次测试方法。
如果在测试方法里同时使用parameters和dataProvider会怎么样?

public class ParameterTest2 {
       
       @Parameters({"param1","param2"})
       @Test(dataProvider="provider1")
       public void test1(String param1,String param2) {
              System.out.println("获取到参数param1:"+param1+",NO."+param2);
       }
       @DataProvider(name="provider1")
       public Object[][] getParams() {
              return new String[][] {
                     {"China","1"},
                     {"Italy","2"}
              };
       }
}

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite1">
       <test name="test1">
              <parameter name="param1" value="Anna"></parameter>
              <parameter name="param2" value="lxh"></parameter>
              <classes>
                     <class name="lxh.test.parameter.ParameterTest2"></class>
              </classes>
       </test>
</suite>

执行结果:

在这里插入图片描述
可以看出来parameters失效没有被执行,所以同时使用的时候,dataProvider的优先级是高于parameters的。
dataProvider也可以跨类调用,如果一个参数集可以被多个用例使用(可复用)的情况下,可以设计成一个参数集类,这样也有利于区分测试代码的角色(用例、参数、调度等等)。

public class DataProvider1 {
       
       @DataProvider(name="provider2")
       public Object[][] getParams() {
              return new String[][] {
                     {"China","1"},
                     {"Italy","2"},
                     {"USA","3"}
              };
       }
}

测试类:

public class ParameterTest2 {
       
//     @Test(dataProvider="provider1")
//     public void test1(String param1,String param2) {
//            System.out.println("获取到参数param1:"+param1+",NO."+param2);
//     }
       
       @Test(dataProvider="provider2",dataProviderClass=DataProvider1.class)
       public void test2(String param1,String param2) {
              System.out.println("获取到参数param1:"+param1+",NO."+param2);
       }
       
       @DataProvider(name="provider1")
       public Object[][] getParams() {
              return new String[][] {
                     {"China","1"},
                     {"Italy","2"}
              };
       }
}

执行结果:
在这里插入图片描述
4.忽略测试
忽略测试意思就是这个测试不需要执行,可以忽略掉,一般在测试用例还没写完或者是暂时不需要进行测试的时候。
用法就是在test注解里面加上enabled=false去禁用这个用例

       @Test(enabled=false)
       public void test3() {
              System.out.println("这个用例还没有设计好不会被执行");
       }

5.超时测试
这个功能其实是在做性能测试的时候会用到,判断测试对象的执行时间是否符合预期,如果超出预期时间就是不通过测试,如果没有超时就说明满足性能要求。
使用方式是在test注解里面定义超时预期值(毫秒)

public class TimeOutTest1 {
       
       /**
        * 实际值1000<预期值2000  可通过
        * @throws InterruptedException
        */
       @Test(timeOut=2000)
       public void test1() throws InterruptedException {
              Thread.sleep(1000);
       }
       /**
        * 实际值2000=预期值2000  可通过
        * @throws InterruptedException
        */
       @Test(timeOut=2000)
       public void test2() throws InterruptedException {
              Thread.sleep(2000);
       }
       
       /**
        * 实际值3000>预期值2000 不通过
        * @throws InterruptedException
        */
       @Test(timeOut=2000)
       public void test3() throws InterruptedException {
              Thread.sleep(3000);
       }
}

执行结果(单类执行):
在这里插入图片描述

也可以在testng.xml里面去设置suite级别的超时时间。

6.依赖测试
这个功能在有流程测试的时候非常实用,依赖测试可以定义用例之间的依赖关系和顺序,也可以使用硬依赖和软依赖的声明来做数据流的测试,个人认为是很漂亮的一个功能。
testng提供两种依赖级别,一种是方法层的(依赖与某个测试方法/在某个测试方法执行后执行),一种是分组层的(依赖与某个分组/在某个测试分组执行完毕后执行)。
方法依赖:

在这里插入图片描述

执行结果:
在这里插入图片描述
分组依赖:
分组依赖和方法依赖是可以交叉使用的

public class DependsTest1 {
       @Test(groups= {"gp1"},dependsOnMethods="test1")
       public void test3() {
              System.out.println("用例3执行完毕!");
       }
       @Test(groups= {"gp1"})
       public void test1() {
              System.out.println("用例1执行完毕!");
       }
       @Test(dependsOnGroups="gp1",dependsOnMethods="test4")
       public void test2() {
              System.out.println("用例2执行完毕!");
       }
       @Test(dependsOnGroups="gp1")
       public void test4() {
              System.out.println("用例4执行完毕!");
       }
}

执行结果:
在这里插入图片描述
上面说到硬依赖和软依赖,指的是在做依赖测试的时候,如果上一个依赖节点执行不成功时,是否强制执行下一个节点,硬依赖(不声明alwaysRun属性的时候默认是硬依赖)情况下不会执行下一节点(引用了依赖的节点),如上面的用例中test1如果执行不成功,test3及以后的方法都将不执行,软依赖的情况下(声明alwaysRun=true)如果被依赖节点执行失败,还会强制执行下一个节点。一般在需要走流程测试/数据流测试的时候,建议用硬依赖。

四、并行测试/多线程测试

testNG里面可以在suite层去定义parallel属性也设置测试运行方式,默认是none串行模式,如果要设置多线程执行,testNG有四个级别的并行模式:
methods方法层,testNG会在多个线程中运行多个用例方法,如果设置了测试依赖,依赖的方法会在同一个线程里按顺序执行。
tests层,同一个test里面的所有用例方法都将在同一个线程里执行,多个test会有多个线程去执行。
classes层,同一个类中的所有用例方法都将在同一个线程中执行,每个class都会有单独的线程执行。
最后一个instance层我还不知道是一个什么级别,意思和上面的都差不多,每个实例一个线程,但是这个实例是指什么实例我还没搞清楚,暂时还没查到,欢迎补充。
testNG里面如果设置了多线程测试,那么可以设置线程数,用thread-count属性去设置线程数。
这里的多线程测试还需要看看源码,目前只能知道大概用法。

五、testNG其他配置

这部分的配置说明可以去看看官网文档,结合实际情况去配置使用吧,度娘会有很详细的答案,这里不详细举例说明了。

end:基本按照以上步骤走一遍,再结合源码看看,testNG对于Java开发来说还是非常简单易懂的,非开发也很好上手。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值