TestNG是Test Next Generation的缩写,它的灵感来自于JUnit和NUnit,在它们基础上增加了很多很牛的功能,比如说:
- 注解。
- 多线程,比如所有方法都在各自线程中,一个测试类一个线程等。
- 验证代码是否多线程安全。
- 灵活的测试配置。
- 支持数据驱动(@DataProvider)。
- 支持参数化。
- 强大的执行机制(不需要TestSuite)。
- 能跟各种工具结合(比如IDEA、Maven等)。
- 内嵌BeanShell。
- 提供运行时和日志的JDK函数(不需要添加dependencies)。
- 提供应用服务器测试依赖的方法。
一句话总结就是,TestNG强大到能覆盖所有测试类型:单元测试、功能测试、端到端测试、集成测试等等等。
一个简单的示例如下:
- setUp()会在测试类创建后,测试方法执行前运行。
- 测试方法名字可以任意的,TestNG通过@Test注解来标识。
- 可以把测试方法按group分组。
然后使用xml来配置运行策略:
使用ant调用(下面第2节给出了最新的运行方式):
最后就能看报告了:
除了前面提到的ant调用,更常见的运行TestNG的方式是以下两种:
- IDEA
- Maven
在IDEA中运行TestNG第①种方式是点击方法或类前面的小箭头:
第②种方式是在方法或类内部点击右键:
第③种方式是使用testng.xml,IDEA可以右键testng.xml来运行,在文件名和文件内部点击均可:
testng.xml支持很多种配置,比如配置测试类:
配置测试包:
配置组和方法:
默认TestNG会按xml顺序执行,可以设置 为false变成随机顺序:
官方教程给出了命令行执行TestNG:
实际调用是调不通的,可以借助Maven来实现。
先在pom.xml添加:
然后执行命令就行啦。
使用了@Test注解的方法就是测试方法,包含测试方法的类就是测试类。比如:
@Test也能放在测试类上面,这样测试类下的所有方法都是测试方法,比如:
而且可以在测试类和测试方法上同时使用@Test,比如给某个Test加入分组:
有个点需要注意的是@Test注解的测试方法,默认是会忽略返回值的,除非在testng.xml配置:
测试组其实就是给测试方法打标记,比如冒烟测试用例和功能测试用例:
如果只配置functest,就会执行全部测试方法:
如果只配置checkintest,就会只执行前面2个方法:
除了指定完整name,也可以使用正则表达式:
进一步,测试组除了include测试方法,还可以exclude:
还有一个办法是使用@Test和@Before/After的属性。
测试组也能进行嵌套:
定义了父分组,里面的就是子分组。
同样的,嵌套分组也可以对子分组进行exclude:
最后,对于分组的位置,如果测试类和测试方法都标记了分组,那么测试类的分组会作用到所有方法中,比如:
method2()属于checkin-test分组,method1属于func-test和checkin-test两个分组。
TestNG参数化有两种方式,第一种是从testng.xml读取数据,第二种是通过代码读取数据。
直接看示例:
- @Parameters指定参数化名字。
- 测试方法入参与参数化名字一一对应。
- testng.xml中定义参数化的值。
在testng.xml中,既可以定义在中也可以定义在中,如果有同名的,会以的覆盖。
@Parameters既可以作用到,也可以作用到 和,比如:
也可以作用到测试类的构造方法中,但是只能最多一个构造方法,这样就能在初始化类的时候,进行参数化赋值,便于测试方法使用
@Optional用于标识参数是否可选,比如:
- 如果db这个参数取不到名字,那么就会取mysql的值。
第一种参数化方式其实比较鸡肋,第二种方式才是TestNG参数化的灵魂,用到了@DataProvider,它会返回一个二维数组:
- @DataProvider用于生产数据,name是唯一标识。
- 在@Test中通过dataProvider属性指定name。
- 测试方法的入参跟数组中元素一一对应。
默认@DataProvider和@Test是在同一个类中,如果想放在不同的类,那么需要定义为静态方法(或者无参数构造方法的类),比如:
- createData()为static。
- 需要额外通过@Test的dataProviderClass属性指定@DataProvider所在的类。
@DataProvider的返回值(参数类型)除了已经提到的,还可以是,它不会一次性生成所有数据,而是每调用一次生成一次,节约内存,比如:
看到这里,对@DataProvider已经有了足够的认识,它支持两种参数类型:
假如测试方法只有一个入参,是不是只能用二维来实现:
其实不是,@DataProvider支持一维数组:
以及一维数组的迭代器:
最精彩的来了,@DataProvider支持反射,也就是反向获取测试方法的信息:
- createData的入参是java.lang.reflect.Method,这样就能获取到测试方法的信息,比如这里的getName()会依次拿到test1、test2。
@DataProvider还支持并发:
默认是10个线程,可以在testng.xml中修改:
一个xml共享一个线程池,如果要用多个线程池,那么需要创建多个testng.xml。
锦上添花的是,TestNG的参数化会打印在测试报告中:
TestNG用例的执行顺序有两种方式来指定:注解和XML。
使用@Test的dependsOnMethods属性:
或者dependsOnGroups属性:
@Before/After也能实现初始化,但是它们的结果不会出现在测试报告中。
默认TestNG会强制校验,依赖的用例必须成功才会执行当前用例,否则当前用例会被标记为SKIP,这叫做强依赖。通过设置alwaysRun=true可以变成弱依赖,无论依赖用例执行成功与否,都会执行当前用例。
需要特别注意的是,依赖测试方法是按照测试类来进行执行的(group by class),比如b()方法依赖的a()方法有多个实例,那么会按照以下顺序执行:
举个实际的例子,登入和登出,如果想达到以下效果:
那么需要在XML中进行配置:
在testng.xml中使用和来指定用例顺序:
假设有这样的测试用例,在测试时需要对网页访问多次,那么在TestNG中会这样编写代码:
- 由于访问次数不一,在testng.xml中定义了3个test,然后借助参数化将访问次数传给@Test测试方法。
- 在@Test测试方法中循环遍历numberOfTimes。
这种需求可以采用TestNG的Factory来对代码进行简化:
- WebTestFactory是工厂函数,返回Object[]。
- WebTestFactory动态创建了多个WebTest实例。
既可以在IDEA中点击WebTestFactory的运行按钮执行测试:
注意如果执行WebTest,会提示No tests were found。
也可以在testng.xml中驱动:
还可以直接在代码中驱动:
@Factory和@Test一样,都能使用dataProvider属性,比如:
TestNG可以使用@Ignore注解忽略测试,比如:
如果作用到测试类上,那么它会忽略这个类下面的所有测试方法。如果只作用到测试方法上,那么它就相当于@Test(enabled=false)。另外还能放在包上面:
可以给@Test添加属性,让用例以多线程并行执行:
- threadPoolSize指3个线程。
- invocationCount指运行10次。
- timeOut指阻塞等待超时。
也可以在testng.xml中设置,thread-count指定线程数,parallel设置不同的值有不同的含义:
methods:
所有测试方法在不同的独立线程中执行。
tests:
标签内的测试方法会在同一个线程中执行,不同的标签会在不同的独立线程中执行。
classes:
同一个类中的测试方法会在同一个线程中执行,不同的类会在不同的独立线程中执行。
instances:
同一个实例中的测试方法会在同一个线程中执行,不同的实例会在不同的独立线程中执行。(Factory能创建多个实例)
TestNG在运行后会把失败的用例输出到文件中,可以直接运行这个文件来重跑失败用例。
夸一句,这个设计真棒。
有时候,需要让用例失败时自动重试,那么可以在代码中这样实现:
- 实现IRetryAnalyzer接口的retry方法。
- 在@Test的retryAnalyzer中指定重试类。
除了IDEA和Maven这两种运行方式,TestNG还可以直接在程序中调用运行:
- TestListenerAdapter是默认的,可以实现org.testng.ITestListener接口自定义TestListener。
- setTestClasses添加测试类。
- run()运行。
还可以通过编程创建一个虚拟的testng.xml,org.testng.xml包的XmlClass, XmlTest等提供了这个能力:
这段代码会创建一个这样的testng.xml:
XmlSuite可以通过TestNG程序调用:
是的,TestNG的XML中可以写BeanShell,用来替代和:
- CDATA用来防止跟XML标签语法冲突。
- 预置了method(当前测试方法)、testngMethod(当前测试方法的描述)、groups(当前测试方法所属分组)三个对象,可以用来做匹配。
- 使用后,和会失效。
TestNG提供了很多Listener用来自定义TestNG行为,类似于Hook那个意思:
- IAnnotationTransformer
- IAnnotationTransformer2
- IHookable
- IInvokedMethodListener
- IMethodInterceptor
- IReporter
- ISuiteListener
- ITestListener
- ITestNGListener
- IAlterSuiteListener
比如用IAnnotationTransformer动态设置@Test属性:
如果想修改@Factory或@DataProvider,得用IAnnotationTransformer2。
比如用IMethodInterceptor设定用例组的执行顺序:
比如想自定义测试开始前和测试后的行为,可以先写个Listener:
然后在测试类上添加:
这样就不用每个测试类都写@BeforeClass和@AfterClass了。
TestNG支持在测试方法中添加特定类来进行依赖注入(就是获取TestNG相关信息):
- ITestContext
- XmlTest 当前标签
- Method 当前调用的测试方法
- Object[] 当前测试方法的入参
- ITestResult 当前测试结果
不同注解支持的方式如下表所示:
示例:
@NoInjection用于禁止依赖注入。
TestNG支持Java的assert关键字断言,示例:
也可以用JUnit断言方法:
用Listener来实现,直接看代码:
TestNG自带了一个测试报告,运行完后会生成index.html,打开就是,比较丑,推荐用Allure。
如果想获取测试报告的数据,那么可以从org.testng.IReporter接口的方法:
根据它的入参去拿。
如果想给测试报告添加数据,那么可以使用org.testng.Reporter类:
如果你烦透了XML,那么可以试试YAML。
比如XML:
换成YAML:
舒服多了。不过TestNG本身没有引入YAML依赖包,需要自己添加:
看完了官方教程,感觉测试框架的功能基本上大同小异,只是技术实现上有所区别。让我惊喜的是,TestNG运行失败的用例可以自动生成一份失败用例的xml文件,直接拿来重跑就可以了。还有一直以为TestNG只能用XML,没想到也能用YAML了。最后,它给出了这个参数,猜猜它是干嘛的。有时候只想看跑起来会执行哪些测试,而不想真正执行,那么就可以用这个参数。
参考资料:
https://testng.org/doc/
https://testng.org/doc/documentation-main.html
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/java-jiao-cheng/10337.html