文章目录
一,TestNG总结
1,TestNG介绍
什么是TestNG
TestNG,即Testing Next Generation,它派生自JUnit和NUnit,除了继承了两者的优势之外,又额外的发展出了一些新的功能,在参数化测试,依赖测试和套件测试(分组概念)方面更加突出。 TestNG用于高级测试和复杂集成测试。
为什么用TestNG
TestNG有以下优点:
生成美观易读的测试报告
注解 使测试变得更加方便
可以更轻松地对测试用例进行分组和指定执行顺序
支持并发测试
生成日志
数据驱动测试
与主流工具的成熟集成
TestNG如何在maven中引用
1、TestNG的常见测试用例组织结构如下:
(1)、Test Suite由一个或者多个Test组成。
(2)、Test由一个或者多个测试Class组成。
(3)、一个测试Class由一个或者多个测试方法组成。
2、TestNG的常用注解如下:
@BeforeSuite 注解的方法将只运行一次,在当前测试集合(Suite)中所有测试用例开始运行之前执行。
@AfterSuite 注解的方法将只运行一次,在当前测试集合(Suite)中所有测试用例运行结束之后执行。
@BeforeTest 注解的方法将在Test中所有测试用例开始运行之前执行。
@AfterTest 注解的方法将在Test中所有测试用例运行结束之后执行。
@BeforeGroups 注解的方法将在分组测试用例的所有测试用例开始运行之前执行。
@AfterGroups 注解的方法将在分组测试用例的所有测试用例运行结束之后执行。
@BeforeClass 注解的方法将在当前测试类(class)的第一个测试方法开始调用前执行。
@AfterClass 注解的方法将在当前测试类(class)的所有测试用例运行结束之后执行。
@BeforeMethod 注解的方法将在每个测试方法开始运行前运行。
@AfterMethod 注解的方法将在每个测试方法运行结束之后执行。
@DataProvider 提供数据的一个测试方法。注解的方法必须返回一个Object[] [],其中每个对象[]的测试方法的参数列表中可以分配。该@Test 方法希望从这个DataProvider的接收数据,需要使用一个dataProvider名称等于这个注解的名字。
@Factory 返回TestNG测试类的对象将被用于标记的方法。该方法必须返回Object[]。
@Listeners 定义一个测试类的监听器。
@Parameters 介绍如何将参数传递给@Test方法。
@Test 标记一个测试方法(测试用例)。
二,详细的常用注解
@Test
Suite,Test,Class,Method注解方法的执行顺序
注解方法的执行顺序
关于Suite,Test,Class,Method的理解
Suite是在TestNG的xml中定义的,可以包含好多个Test,Test也是在TestNG的xml中定义的,可以包含好多个class。class是我们的自动化Java类,可以包含多个Method。
下面是一个包含Suite,Test,Class,Method的例子
测试程序文件
package first;
import org.testng.annotations.*;
class TestOrder {
@BeforeSuite
public void bs(){
System.out.println("----before suite----");
}
@BeforeTest
public void bt(){
System.out.println("----before test----");
}
@BeforeClass
public void bc(){
System.out.println("----before class----");
}
@BeforeMethod
public void bm(){
System.out.println("----before method----");
}
@Test
public void test1(){
System.out.println("----in test1----");
}
@Test
public void test2(){
System.out.println("----in test2----");
}
@AfterMethod
public void am(){
System.out.println("----after method----");
}
@AfterClass
public void ac(){
System.out.println("----after class----");
}
@AfterTest
public void at(){
System.out.println("----after test----");
}
@AfterSuite
public void as(){
System.out.println("----after suite----");
}
}
testng.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite">
<test name="Test1">
<classes>
<class name="first.TestOrder" />
</classes>
</test>
<test name="Test2">
<classes>
<class name="first.TestOrder" />
</classes>
</test>
</suite>
运行结果如下:
[TestNG] Running:
D:\workspace\FirstPro\testng.xml
----before suite----
----before test----
----before class----
----before method----
----in test1----
----after method----
----before method----
----in test2----
----after method----
----after class----
----after test----
----before test----
----before class----
----before method----
----in test1----
----after method----
----before method----
----in test2----
----after method----
----after class----
----after test----
----after suite----
===============================================
Suite
从上面的执行结果就可以看出来测试程序的逻辑结构是这样的:
1.测试程序最外层是Suite,在执行Suite之前执行BeforeSuite,执行之后执行AfterSuite
2.每个Suite有多个Test组成,在每个Test执行之前执行BeforeTest,执行之后执行AfterTest
3.每个Test由多个Class组成,在每个Class执行前执行BeforeClass,执行之后执行AfterClass
4.每个Class由多个Method组成,在每个Method执行前执行BeforeMethod,执行之后执行AfterMethod
TestNG,@Test(enabled = false),@Test(timeout=)忽略测试和超时测试
TestNG忽略测试
有时,我们的代码是没有准备好,如果测试用例写入到测试方法/代码将无法运行,在这种情况下,@Test(enabled = false)有助于禁用此测试用例执行
使用例子
public class TestEnable {
@Test
public void testcase1(){
System.out.println("testcase1");
}
@Test(enabled = false)
public void testcase2(){
System.out.println("testcase2");
}
@Test
public void testcase3(){
System.out.println("testcase3");
}
}
运行结果
[TestNG] Running:
C:\Users\Administrator\.IntelliJIdea2016.3\system\temp-testng-customsuite.xml
testcase1
testcase3
从上面可以看到testcase2已经被忽略掉了
TestNG超时测试
当一个测试用例里面有某些部分会导致耗时异常,比如里面有个循环,导致死循环,那么我们不可能一直在这个测试用例等待这个用例运行,我们可以设定预定的用例执行最大时间,超出这个时间,这个用例就认为失败,接着运行下面的测试用例。
达到这个目的,我们可以使用@Test(timeout=)来实现
使用例子
public class TestTimeOut {
@Test(timeOut = 1000)
public void testcase1(){
try {
Thread.sleep(999);
System.out.println("testcase1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Test(timeOut = 1000)
public void testcase2(){
try {
Thread.sleep(2000);
System.out.println("testcase2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Test
public void testcase3(){
System.out.println("testcase3");
}
}
运行结果
[TestNG] Running:
C:\Users\Administrator\.IntelliJIdea2016.3\system\temp-testng-customsuite.xml
testcase1
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.testproj.Demo.TestTimeOut.testcase2(TestTimeOut.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
at org.testng.internal.InvokeMethodRunnable.runOne(InvokeMethodRunnable.java:46)
at org.testng.internal.InvokeMethodRunnable.run(InvokeMethodRunnable.java:37)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
org.testng.internal.thread.ThreadTimeoutException: Method org.testng.internal.TestNGMethod.testcase2() didn't finish within the time-out 1000
at java.lang.Throwable$PrintStreamOrWriter.<init>(Throwable.java:728)
at java.lang.Throwable$PrintStreamOrWriter.<init>(Throwable.java:728)
at java.lang.Throwable$WrappedPrintStream.<init>(Throwable.java:739)
at java.lang.Throwable.printStackTrace(Throwable.java:643)
at java.lang.Throwable.printStackTrace(Throwable.java:634)
at com.testproj.Demo.TestTimeOut.testcase2(TestTimeOut.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
at org.testng.internal.InvokeMethodRunnable.runOne(InvokeMethodRunnable.java:46)
at org.testng.internal.InvokeMethodRunnable.run(InvokeMethodRunnable.java:37)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
testcase3
===============================================
Default Suite
Total tests run: 3, Failures: 1, Skips: 0
===============================================
异常测试
什么是异常测试?
若测试方法抛出了预期的异常,则测试通过。
什么时候用到异常测试?
当我们的期望结果为某个异常的时候
如何使用?
@Test(expectedExceptions = 预期异常.class)
TestNG通过 @Test(expectedExceptions) 来判断期待的异常, 也可以判断Error Message
@Test(expectedExceptions = IllegalArgumentException.class,expectedExceptionsMessageRegExp = "非法参数")
public void testException(){
throw new IllegalArgumentException("非法参数");
}
案例
import org.testng.annotations.Test;
public class ExpectedExceptionTest {
//没有预期异常
@Test
public void testcase1(){
throw new RuntimeException();
}
// 有预期异常,但是测试方法没有抛出该异常
@Test(expectedExceptions = RuntimeException.class)
public void testcase2(){
System.out.println("这是一个失败的异常测试");
}
// 有预期异常,且测试方法抛出了该异常
@Test(expectedExceptions = RuntimeException.class)
public void testcase3(){
System.out.println("这是一个成功的异常测试");
throw new RuntimeException();
}
}
执行ExpectedExceptionTest 类,结果如下
查看testcase1,执行信息
查看testcase2,执行信息
这是一个失败的异常测试
org.testng.TestException:
Method ExpectedExceptionTest.testcase2()
[pri:0,instance:com.course.testng.suite.ExpectedExceptionTest@2ef9b8bc]
should have thrown an exception of type class java.lang.RuntimeException
查看testcase3,执行信息
这是一个成功的异常测试
使用例子
public class TestExpectedException {
@Test
public void testcase1(){
throw new ExceptionInInitializerError();
}
@ExpectedExceptions(value = ExceptionInInitializerError.class)
@Test
public void testcase2(){
throw new ExceptionInInitializerError();
}
@Test(expectedExceptions = ExceptionInInitializerError.class)
public void testcase3(){
throw new ExceptionInInitializerError();
}
}
其中@ExpectedExceptions(value = ExceptionInInitializerError.class)进行注解是不建议使用的,我们一般通过@Test(expectedExceptions=异常类)进行使用
测试结果
依赖测试
一,dependsOnMethods:
通过方法名给出测试方法的依赖关系
正常的测试用例顺序应该是test1>test2>test3>test4
这里在test1写了依赖关系为test4,所以此时运行后的结果是如图中test4>test2>test3>test1
依赖关系的规则是:1, 优先被依赖关系方法
2,没有依赖关系的
3,需要依赖关系的
dependONmethods的异常抛出 :
二,dependONgroups(以组名方式测试依赖方法)
对于多个被依赖的测试方法,可以通过方法名直接给出(dependsOnMethods = {“test2”,“test3”}),也可以通过组名给出被依赖的测试方法。
组名添加:@Test(groups={“组名称”})
@Test(dependsOnGrops=“组名”)
注:方法名时用的是{};
三,通过xml文件配置组名依赖方法( 主要是测试组的用法)
测试组:一个组可包含多个测试方法,可进行组嵌套
1,test1属于功能测试,test02属于接口测试,test03属于接口和功能测试 ,test4是不属于任何组
2,仅运行API测试 时,xml文件的配置
结果是只运行了API方法的测试用例,如果只运行功能测试,这时把api换成function即可
3,运行API和功能测试的用例方法
从结果可看出 test4不属于任何用户组 所以没有运行,inclulde 用于执行多个测试组用例的执行
4,exclude :执行除了某用例之外的其他用例
例如,执行除了API接口的其他用例
5,利用正则表达式来写组名
这里先把组名API改成了 API test
正则用来代替组名较长的时候
6,组嵌套
每个用例都要归属于 一个组名,所有组都归All管理,这样xml run一个All 即可
7,根据xml配置文件中的 groups 的来做用例组依赖执行
xml配置文件配置如下
测试用例组的顺序是:先执行被依赖的组的方法用例,再执行没有依赖关系的 最后执行需要依赖关系的用例方法;
testng.xml 方式和@DataProvider,参数化测试
TestNG提供了2种传递参数的方式。
第一种: testng.xml 方式使代码和测试数据分离,方便维护,适用于一个用例,需要多个相同参数(值不同)来验证的情况。
第二种:@DataProvider能够提供比较复杂的参数。
如下例:
第一种,@Parameters({ “merchantNo” }) 会去testng.xml里取到这个merchantNo对应的value,放到传参merchant中
public class TestParameter {
// @Parameters注解内对应的参数名称和配置文件中的merchantNo必须是相同
// 如果在配置文件中找不到参数名称为“merchantNo”的参数,则测试方法将接收@Optional注解中指定的默认值:“chen001”
@Parameters({ "merchantNo" })
@Test
public void testString(@Optional("chen001")String merchant) {
System.out.println("Invoked testString " + merchant);
assert "chen001".equals(merchant);
}
}
对应的testng.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<suite name="TestNg">
<parameter name="merchantNo" value="chen001"/>
<test name="TestParameter">
<classes>
<class name="com.example.testng_demo.TestParameter"/>
</classes>
</test>
</suite>
第二种,注解@DataProvider在参数化测试中起到重要的作用,该注解下的函数返回数据类型有两种,一种返回类型是Iterator<Object[]>,还一种返回类型是 Object[][],看例子如何实现:
@DataProvider函数,需要定义属性name
@DataProvider(name = "testcase")
public Iterator <Object[]> createData2() {
List <Object[]> datas = new ArrayList <Object[]>();
datas.add(new Object[]{"payment"});
datas.add(new Object[]{"refund"});
datas.add(new Object[]{"check"});
return datas.iterator();
}
@DataProvider(name = "testcase2")
public Object[][] createData1() {
return new Object[][] {
{ "Cedric", new Integer(36) },
{ "Anne", new Integer(37)},
};
}
@Test测试用例,属性dataProvider需要指定对应的@DataProvider名称
@Test(dataProvider = "testcase")
public void verifyData2(String type) {
System.out.println(type);
}
@Test(dataProvider = "testcase2")
public void verifyData1(String n1, Integer n2) {
System.out.println(n1 + " " + n2);
}
输出:
Cedric : 36
Anne : 37
payment
refund
check
多线程运行
// 共3个线程调用了10次该方法
@Test(threadPoolSize = 3, invocationCount = 10,timeOut = 3000)
public void testThread(){
System.out.println(Thread.currentThread().getId());
}
invocationCount——-表示执行的次数
threadPoolSize——-表示线程池内线程的个数
timeOut——-超时时间-毫秒
分组测试
相比junit的TestCase/TestSuite,TestNG有suite/test/test method三个级别,即将test/test method明确区分开了。
suite由xml文件描述。它包含一个或多个测试并被定义为标签
test由描述并包含一个或者多个TestNG类
TestNG类是包含至少一个TestNG annotation的java类,由标签描述并包含一个或多个测试方法
测试类:
public class Testng {
@Test(groups = { "functest", "checkintest" })
public void testMethod1() {
System.out.println("testMethod1");
}
@Test(groups = {"functest", "checkintest"} )
public void testMethod2() {
System.out.println("testMethod2");
}
@Test(groups = { "functest" })
public void testMethod3() {
System.out.println("testMethod3");
}
}
testng.xml文件:
<?xml version="1.0" encoding="UTF-8" ?>
<suite name="TestNG">
<test name="Test1">
<groups>
<run>
<include name="checkintest"/>
</run>
</groups>
<classes>
<class name="com.example.testng_demo.Testng"/>
</classes>
</test>
</suite>
意思就是执行Testng类中groups包含checkintest的方法,testMethod3这个方法的groups不含checkintest,所以不会执行;
TestNG中的测试用例编写过程
在TestNG中编写测试非常简单,基本上包括以下步骤:
第1步 - 编写测试的业务逻辑
第2步 - 在代码中插入TestNG注解
第3步 - 在testng.xml文件中添加有关测试的信息(例如,类名,方法名,组名等)
第4步 - 运行TestNG
TestNG 常用注解
@BeforeSuite:在此套件中的所有测试运行之前,将运行带注释的方法。
@AfterSuite:在此套件中的所有测试运行后,将运行带注释的方法。
@BeforeTest:在运行属于标记内的类的任何测试方法之前,将运行带注释的方法。
@AfterTest:在标记内的类的所有测试方法都运行之后,将运行带注释的方法。
@BeforeGroups:此配置方法之前将运行的组列表。保证在调用属于任何这些组的第一个测试方法之前不久运行此方法。
@AfterGroups:此配置方法将在之后运行的组列表。保证在调用属于任何这些组的最后一个测试方法后不久运行此方法。
@BeforeClass:在调用当前类中的第一个测试方法之前,将运行带注释的方法。
@AfterClass:在运行当前类中的所有测试方法之后,将运行带注释的方法。
@BeforeMethod:带注释的方法将在每个测试方法之前运行。
@AfterMethod:带注释的方法将在每个测试方法之后运行。
@Test:带注释的方法是测试用例的一部分。
生命周期:
@BeforeSuite->@BeforeTest->@BeforeClass->{@BeforeMethod->@Test->@AfterMethod}->@AfterClass->@AfterTest->@AfterSuite
TestNG常用断言
导入Assert包:
import static org.testng.Assert.*;
assertTrue:判断是否为True。
assertFalse:判断是否为false。
assertSame:判断引用地址是否相同。
assertNotSame:判断引用地址是否不相同。
assertNull:判断是否为null。
assertNotNull:判断是否不为null。
assertEquals:判断是否相等,Object类型的对象需要实现haseCode及equals方法。
assertNotEquals:判断是否不相等。
assertEqualsNoOrder:判断忽略顺序是否相等。