03 TestNG框架与Junit的区别简介与使用-基本注解使用、套件测试、参数化测试、分组测试、依赖测试、多线程测试等

3,930 阅读10分钟

1、What is TestNG?

1.1 什么是TestNG?

下面这段英文是testNG官方给出的说明:

TestNG is a testing framework inspired from JUnit and NUnit but introducing some new functionalities that make it more powerful and easier to use, such as:

  • Annotations.
  • Run your tests in arbitrarily big thread pools with various policies available (all methods in their own thread, one thread per test class, etc...).
  • Test that your code is multithread safe.
  • Flexible test configuration.
  • Support for data-driven testing (with @DataProvider).
  • Support for parameters.
  • Powerful execution model (no more TestSuite).
  • Supported by a variety of tools and plug-ins (Eclipse, IDEA, Maven, etc...).
  • Embeds BeanShell for further flexibility.
  • Default JDK functions for runtime and logging (no dependencies).
  • Dependent methods for application server testing.

TestNG is designed to cover all categories of tests: unit, functional, end-to-end, integration, etc...

1.2 Junit与TestNG的注解区别:

功能 Junit TestNG
标注为类/方法为测试类和方法 @Test @Test
标注为在suite中所有测试之前运行 @BeforeSuite
标注为在suite中所有测试之后运行 @AfterSuite
标注为在测试之前运行 @BeforeTest
标注为在测试之后运行 @AfterTest
标注为再试Group中第一个测试方法之前运行 @BeforeGroups
标注为再试Group中第一个测试方法之后运行 @AfterGroups
标注为当前测试类中第一个测试方法之前运行 @BeforeClass @BeforeClass
标注为当前测试类中最后一个测试方法之后运行 @AfterClass @AfterClass
标注为在每次测试方法之前运行 @Before @BeforeMethod
标注为在每次测试方法之后运行 @After @AfterMethod
忽略某测试,让其不执行 @Ignore @Test(enable=false)
期待测试抛出什么异常 @Test(excepted=XXXException.class) @Test(exceptedExceptions=XXXException.class)
测试超时,如果测试的执行时间超过了毫秒为单位设置的时间 @Test(timeout=1000) @Test(timeout=1000)

1.3 区别总结

由上述介绍总结几点TestNG和Junit主要的区别和适合测试工程师使用的原因:

  • TestNG是比Junit涵盖功能更全面的测试框架,具有参数化和分组的特性,可以做数据驱动
  • Junit更适合隔离性比较强的单元测试
  • TestNG被设计应与覆盖所有的测试,单元、功能、端到端、集成测试等
  • TestNG依赖测试时对于依赖方法失败后的用例标记为跳过而不是像Junit标记为失败,减少失败原因排查成本
  • TestNG可以针对失败用例回归测试,增加测试针对性和效率,而Junit需要将所有测试用例重新执行
  • TestNG更适合测试工程师需要的大范围的复杂的继集成测试

:以上对比指的是TestNG和Junit4版本的对比,最新的Junit5框架已经完善了功能特性,涵盖了TestNG所包含的功能,可以直接选用Junit5作为测试框架,只是Junit5还在推广普及中;具体可参考另外一篇博客: Junit5简介、构成、新特性及基本使用-常用注解、套件执行

2、注解使用与实操

maven依赖:

		<dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.14.3</version>
            <scope>test</scope>
        </dependency>

2.1 基本测试@Test和@BeforeMethod、@AfterMethod

  • Junit和TestNG对于测试方法的标注都是@Test,另外在方法执行前后加上@BeforeMethod@AfterMethod
    在这里插入图片描述
    测试结果:
    在这里插入图片描述
    由测试结果可看到在每个测试用例执行前都会先执行@BeforeMethod注解的方法,之后都会执行@AfterMethod注解的方法

2.2 @BeforeClass和@AfterClass

在测试类运行之前运行@BeforeClass@AfterClass

在这里插入图片描述
测试结果:
在这里插入图片描述
由测试结果可以看出在测试类执行前后会先后执行一次被@BeforeClass@AfterClass注解的方法

2.3 套件测试

  • TestNG的套件管理有点“特别”,它是以一个xml文件作为统一配置文件的,一般会命名为testNG.xml,实际上文件的命名随意,you happy just ok!
  • 执行时通过运行xml文件
  • 最基本的套件管理规则时:suite->test->classes->class
  • 同一个test下的测试类看做是一个整体,其中的注解对整个test整体都是生效的

下面看实操演示,当前有3个测试类SuiteTest1SuiteTest2SuiteTestConfig

在这里插入图片描述
resource下创建套件配置文件testNGSuite.xml
在这里插入图片描述

2.3.1 套件测试+@BeforeSuite和@AfterSuite

1)在SuiteTest1SuiteTest2测试类中分别输入测试用例:

在这里插入图片描述
在这里插入图片描述
2)再在SuiteTestConfig测试类中输入@BeforeSuite@AfterSuite注解方法和@Test方法
在这里插入图片描述
3)最后在配置文件testNGSuite.xml中配置套件执行顺序 将SuiteTest1SuiteTestConfig"包"成一个test整体,SuiteTest2SuiteTestConfig"包"成一个test整体;然后依顺序执行 ==注:suite和test Tag需要给一个name,否则会报错==
在这里插入图片描述
测试结果:
在这里插入图片描述
从测试结果我们可以看到@BeforeSuite@AfterSuite仅仅在suite执行前后分别执行一次

2.3.2 套件测试+@BeforeTest+@AfterTest
  • 在测试类SuiteTestConfig中输入@BeforeTest+@AfterTest注解的方法,xml套件配置不变
    在这里插入图片描述
    测试结果:
    @BeforeSuite,测试套件运行前执行
    
    @BeforeTest,在test执行前执行    	<------@BeforeTest
    我是suiteTest1
    我是SuiteTestConfig测试case
    @AfterTest,在test执行后执行      	<------@AfterTest
    
    @BeforeTest,在test执行前执行		<------@BeforeTest
    我是suiteTest2
    我是SuiteTestConfig测试case
    @AfterTest,在test执行后执行		<------@AfterTest
    
    @AfterSuite,测试套件执行后执行
    ===============================================
    testNG demo
    Total tests run: 4, Failures: 0, Skips: 0
    ===============================================
    
    由测试结果可以看到,在每个test执行前后都会先后执行一次由@BeforeTest@AfterTest注解的方法

2.4 忽略测试@Test(enable=false)

  • 在测试方法test1的注解中设置属性enable=false
    在这里插入图片描述
    测试结果:
    在这里插入图片描述
    由测试结果可以看到test1被忽略了,并没有执行

2.5 分组测试

2.5.1 方法分组 @Test(groups="xxx")、@BeforeGroups+@AfterGroups
  • 分别将方法test1test2分为“测试1组”和“测试2组
  • 再在测试1组执行前执行@BeforeGroups注解方法,在测试2组执行后执行@AfterGroups注解方法
    在这里插入图片描述
    测试结果:
    在这里插入图片描述
2.5.2 测试类分组 @Test(groups="xxx")
  • 当前有3个测试类 ClassGroups1TestClassGroups2TestClassGroups3Test
    在这里插入图片描述
    1)分别将这3个测试类进行分组Group1Group2Group3
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    2)将这3个测试类以3、2、1的执行顺序引入xml套件配置文件
    		<classes>
                <class name="groups.ClassGroups3Test"/>
                <class name="groups.ClassGroups2Test"/>
                <class name="groups.ClassGroups1Test"/>
            </classes>
    
    3)设置场景,利用配置<groups>-><run>-><include>/<exclude>Group1Group3执行,Group2不执行(实际上如果<groups>中直接不写Group2,它也不会执行)
    		<groups>
                <run>
                    <include name="Group1"/>
                    <exclude name="Group2"/>
                    <include name="Group3"/>
                </run>
            </groups>
    
    xml套件配置文件呈现结果:
    在这里插入图片描述
    测试结果:
    在这里插入图片描述
    由测试结果可以看到,测试类分组在Group3Group1的方法依次执行了,而Group2分组中的测试类未被执行

    **注:**如果测试用例的逻辑顺序设计的较合理,平常使用分组的频率可能没那么高

2.6 异常测试@Test(exceptedExceptions = XXXException.class)

  • 测试时,我们可能期望的结果就是抛出某种异常,比如单元测试时输入非法入参,程序期望抛出异常,而这是期望的正确结果,我们希望用例是测试通过的,这时就需要用到异常测试注解:@Test(exceptedExceptions = XXXException.class)
    在这里插入图片描述
    测试结果:
    在这里插入图片描述

    注: 单元测试平常更多的可能由研发人员自己完成,一般功能和接口测试我们测试工程师期待的都是后端对异常处理后返回的一个状态码code和message信息

2.7 依赖测试@Test(dependsOnMethods = {"funtion name"})

  • 有时候一个用例的执行要依赖其他用例的执行结果,例如购买商品前需要依赖用户登录成功才可以,这个时候就需要使用 @Test(dependsOnMethods = {"funtion name"})对另一个用例进行依赖
    在这里插入图片描述
2.7.1 依赖用例成功

然后我们==直接运行pay方法==,结果如下:

在这里插入图片描述
由测试结果我们可以看到虽然我们直接执行了pay方法,但是由于pay方法是依赖于login方法的,所以会先执行login方法

2.7.2 依赖用例失败
  • 我们让被依赖的login用例执行失败,==直接运行pay方法==,观察结果:
    在这里插入图片描述
    测试结果:
    在这里插入图片描述
    由测试结果可以看到几点现象:
    • 被依赖的用例执行失败,后面的用例会直接跳过忽略
    • 测试结果显示为忽略而不是失败,这样当有成百上千条用例因为被依赖的用例失败而执行不通过时,可以只排查被依赖用例失败原因即可;否则如Junit4全部标记为失败的话会造成排查问题和回归测试效率的极大浪费

2.8 参数化测试

  • 有的方法需要传参,好比登录成功时我们需要用户的姓名和ID号
  • 参数的传递直接写在代码中不利于维护更改,也不方便不懂代码的测试人员进行参数修改,这个时候就需要参数化测试
2.8.1 参数化测试1:@Parameters+<parameter name="xx" value="xxx"/>
  • 这个时候就需要在方法上加上注解@Parameters,并在xml配置文件中利用<parameter name="xx" value="xxx"/>的方式传参

注:也可用<methods><methods/>tag对指定的方法进行参数传递

在这里插入图片描述
xml里完成传参:
在这里插入图片描述
测试结果:
在这里插入图片描述

2.8.2 参数化测试2:@Test(dataProvider = "name")+@DataProvider

1)利用@Test(dataProvider = "name")+@DataProvider(name="name")将多组数据传递到一个方法中依次执行

在这里插入图片描述
测试结果:
在这里插入图片描述
2)利用@Test(dataProvider = "name")+@DataProvider(name="name")指定测试方法,传递指定入参进行测试
在这里插入图片描述
分别单独运行方法userInfo1userInfo2得到测试结果: userInfo1:
在这里插入图片描述
userInfo2:
在这里插入图片描述

2.9 多线程测试

2.9.1 多线程测试注解实现 @Test(invocationCount=10,threadPoolSize=4)

参数说明: 官方给出的解释是如下

在这里插入图片描述

简单来说就是:

  • invocationCount表示方法要运行几次
  • threadPoolSize表示线程池大小,且要配合invocationCount才起作用

现在将userInfo1方法用多线程执行10次,线程池大小设为4,打印当前线程id以观察验证

在这里插入图片描述
测试结果:
在这里插入图片描述
从测试结果中可以看到4个不同的线程一共将方法userInfo1执行了10次

2.9.2 多线程测试xml实现-parallel(methods|tests|classes)+thread-count

参数解释: 官方文档的解释如下:

在这里插入图片描述
在这里插入图片描述

  • parallel(methods|tests|classes):设置使用多线程,且有methods|tests|classes三种不同级别选择
    • methods: 所有用例都可以在不同的线程下执行,包括依赖的用例
    • tests: 同一个<test>中的用例运行在同一个线程下,不同<test>中的用例可以运行在不同线程下
    • classes: 同一个<class>中的用例运行在同一个线程下,不同<class>中的用例可以运行在不同线程下

1)创建3个方法,打印线程ID

在这里插入图片描述
2) 2.1)methods-所有用例都可以在不同的线程下执行

  • 设置parallelmethods级别,thread-count为3,进行测试
    在这里插入图片描述
    测试结果:
    在这里插入图片描述
    2.2)tests-同一个<test>中的用例运行在同一个线程下,不同<test>中的用例可以运行在不同线程下 再创建测试类ThreadTest,添加三个方法并打印thread ID
    在这里插入图片描述
  • 设置paralleltests级别,thread-count为3,进行测试
    在这里插入图片描述
    测试结果:
    在这里插入图片描述
    2.3)classes-同一个<class>中的用例运行在同一个线程下,不同<class>中的用例可以运行在不同线程下
  • 设置parallelclasses级别,thread-count为3,进行测试
    在这里插入图片描述
    测试结果:
    在这里插入图片描述

注: 虽然框架本身说明了是多线程安全的,但是由于我们自身编码可能不能保证严格规范,容易造成多线程不安全,所以建议不要适用多线程测试,而是适用多进程测试

参考链接: TestNG官方说明: testng.org/doc/index.h… IBM Developer: www.ibm.com/developerwo…