TestNg单元测试框架

一,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:判断忽略顺序是否相等。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值