本文已参与「新人创作礼」活动,一起开启掘金创作之路。
TestNG入门
一、概述
1、TestNG是一个开源自动化测试框架
其灵感来自JUnit和Nunit,TestNG还涵盖了整个核心的JUnit4功能,但引入了一些新的功能,使其功能更强大,使用更方便。
优势:支持依赖测试方法,并行测试,负载测试,局部故障;灵活的插件API;支持多线程测试;
2、Maven依赖
idea默认已经安装testng了,检查是否安装:
File ==> Settings ==>Plugins ==> 搜索testng
若已经安装TestNG的插件,显示如下:
若没有,则搜索TestNG,进行下载
Eclipst也可以通过Maven添加
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.7</version>
<scope>test</scope>
</dependency>
注意:Eclipse上想要运行还需要安装testng插件
注意:idea需要安装Create TestNG XML插件
File ==> Setting ==>Plugins ==>搜索Create TestNG XML插件安装 ==> 重启 ==> 选择项目文件夹 ==> 右键Create TestNG XML ==>刷新一下项目就能看到testng.xml文件了
3、helloword
(1)被测试方法类HelloWorld:
package org.ant.test.testcase;
public class HelloWorld {
public String hello(){
return "hello world!";
}
}
(2)测试类TestHelloWorld:
import org.testng.annotations.Test;
public class TestHelloWorld {
// 测试返回结果不为空
@Test
public void tester1(){
HelloWorld hello = new HelloWorld();
String helloworld = hello.hello();
// 检查返回结果
Assert.assertNotNull(helloworld);
}
// 测试返回结果为"hello world!"字符串
@Test
public void tester2(){
HelloWorld hello = new HelloWorld();
String helloworld = hello.hello();
System.out.println(helloworld);
// 检查返回结果是否=hello world!
Assert.assertEquals(helloworld,"Hello world!");
}
}
(3)运行测试
(4)测试结果
二、@Test注解常用参数
1、测试方法是否执行enable
默认是true,如果设置为false,则在运行时不会执行这个测试方法;
例子:将tester1设置为跳过,不执行
@Test(enabled = false)
运行结果:tester1跳过不执行
2、预期异常expectedException
注意:如果ClassName类抛出了异常,测算测试通过,没有异常算测试不通过;
1】单个异常
@Test(expectedExceptions = ClassName.class)
例子:测试被除数为0,抛异常
运行结果:java.lang.ArithmeticException: / by zero
复制ArithmeticException到@Test中设置预期异常,预期结果就是代码抛出异常ArithmeticException,用例通过的话,则通过@Test的expectedExceptions属性,通过该属性指定抛出异常的类
@Test(expectedExceptions = ArithmeticException.class)
再次执行通过
2】expectedExceptions的值也可以是一个数组
@Test(expectedExceptions = {ClassName.class, ClassName2.class,... })
3、超时timeOut
单位毫秒,如果测试方法运行时间超过这个值算测试不通过;
@Test(timeOut = 2000) //单位毫秒
例子:
// 超时测试
@Test(timeOut = 2000) //单位毫秒
public void tester1() throws InterruptedException {
Thread.sleep(5000);
}
// 超时测试测试
@Test(timeOut = 2000)
public void tester2() throws InterruptedException {
Thread.sleep(1000);
}
运行结果:可以看到tester1超时,测试不通过
4、分组groups
1】testNG的分组通过xml文件标签和@Test(groups="组名")来实现分组;
2】xml中通过groups定义一个组,通过标签运行指定的组;
3】分组的最小维度为方法,当把带分组的@Test(groups = ”groupName”)注解对类使用时,这个测试类中的所有方法都属于这同一个组;
4】一个方法也可以同时属于多个组,@Test(groups = {“groupName1”, “groupName2”}),那么每组运行时这个方法都会被执行一次;
5】同一个组里的方法类,如果分别属于两个不同的测试用例()内,那么它们其实可以算两个组,它们会在每个测试用例分别运行,而不会合在一起运行;
5、依赖方法dependsOnMethods
在被依赖的方法运行完成之后运行当前方法,如果依赖方法测试不通过,那么当前方法也不会继续运行了;依赖的方法可以有多个;
例子:methodName1和methodName2是tester1的依赖方法
// 依赖方法
@Test(dependsOnMethods = { "methodName1" ,"methodName2" })
public void tester1() throws InterruptedException {
System.out.println("测试方法tester1");
}
@Test
public void methodName1(){
System.out.println("依赖方法methodName1");
}
@Test
public void methodName2(){
System.out.println("依赖方法methodName2");
}
运行结果:
6、依赖组,dependsOnGroups
和依赖方法类似,在被依赖组运行完成之后,运行当前组,如果依赖组中的方法没有测试通过,那么当前方法也不会继续运行了;依赖组可以有多个;
三、测试中常用的断言(assert)
assertEqual (expected value,actual value,[String message]) //断言两个值相等。值可能是类型有 int, short, long, byte, char or java.lang.Object. 第一个参数是一个可选的字符串消息;
assertTrue(boolean condition,[String message]) //断言一个条件为真;
assertFalse(boolean condition,[String message]) //断言一个条件为假;
assertNotNull(java.lang.Object object,[String message]) //断言一个对象不为空(null);
assertNull(java.lang.Object object,[String message]) //断言一个对象为空(null);
assertSame(java.lang.Object expected, java.lang.Object actual,[String message]) //断言两个对象引用相同的对象;
assertNotSame(java.lang.Object unexpected, java.lang.Object actual,[String message]) //断言两个对象不是引用同一个对象;
assertArrayEquals(expectedArray, resultArray,[String message]) //断言预期数组和结果数组相等。数组的类型可能是 int, long, short, char, byte or java.lang.Object.;
注意:断言中有个message可选参数是断言后要展示的信息,【message各个版本中参数可能顺序不一致】
例子:
@Test
public void methodName1(){
String a = "jkl";
Assert.assertNull(a,"判断字符串a是否为空");
}
运行结果:
四、TestNG常用注解及使用
| 注释 | 功能 |
|---|---|
| @BeforeSuite | 在该套件的所有测试都运行在注释的方法之前,仅运行一次(套件测试是一起运行的多个测试类)。 |
| @AfterSuite | 在该套件的所有测试都运行在注释方法之后,仅运行一次。 |
| @BeforeClass | 在调用当前类的第一个测试方法之前运行,注释方法仅运行一次。 |
| @AfterClass | 在调用当前类的第一个测试方法之后运行,注释方法仅运行一次 |
| @BeforeTest | 注释的方法将在属于标签内的类的所有测试方法运行之前运行。 |
| @AfterTest | 注释的方法将在属于标签内的类的所有测试方法运行之后运行。 |
| @BeforeGroups | 配置方法将在之前运行组列表。 此方法保证在调用属于这些组中的任何一个的第一个测试方法之前不久运行。 |
| @AfterGroups | 此配置方法将在之后运行组列表。该方法保证在调用属于任何这些组的最后一个测试方法之后不久运行。 |
| @BeforeMethod | 注释方法将在每个测试方法之前运行。 |
| @AfterMethod | 注释方法将在每个测试方法之后运行。 |
| @Parameters | 描述如何将参数传递给@Test方法。 |
| @DataProvider | 标记一种方法来提供测试方法的数据。 注释方法必须返回一个Object [] [],其中每个Object []可以被分配给测试方法的参数列表。 要从该DataProvider接收数据的@Test方法需要使用与此注释名称相等的dataProvider名称。 |
| @Factory | 将一个方法标记为工厂,返回TestNG将被用作测试类的对象。 该方法必须返回Object []。 |
| @Listeners | 定义测试类上的侦听器。 |
| @Test | 将类或方法标记为测试的一部分。 |
例子:
1】增加一个测试类TestConfig
package org.ant.test.testcase;
import org.testng.annotations.*;
public class TestConfig {
@BeforeSuite
public void beforeSuite(){
System.out.println("测试套件(当前xml中<suite>标签)之前运行@BeforeSuite------");
}
@AfterSuite
public void afterSuite(){
System.out.println("测试套(当前xml中<suite>标签)之后运行@AfterSuite-------");
}
@BeforeTest
public void beforeTest(){
System.out.println("测试用例(当前xml中<test>标签)之前运行@BeforeTest");
}
@AfterTest
public void afterTest(){
System.out.println("测试用例(当前xml中<test>标签)之后运行@AfterTest--------");
}
@BeforeMethod
public void beforeMethod(){
System.out.println("当前类每个测试方法(@Test)之前运行@BeforeMethod");
}
@AfterMethod
public void afterMethod(){
System.out.println("当前类每个测试方法(@Test)之后运行@AfterMethod");
}
@BeforeGroups(value="group1")
public void beforeGroups(){
System.out.println("配置组配group1之前运行@BeforeGroups..........");
}
@AfterGroups(value="group1")
public void afterGroups(){
System.out.println("配置组配group1之前运行@AfterGroups.......");
}
@Test
public void test1(){
System.out.println("running TestConfig.test1()");
}
@Test
public void test2(){
System.out.println("running TestConfig.test2()");
}
@Test(groups = "group1")
public void test3(){
System.out.println("running TestConfig.test3()");
}
}
2】选择工程右键创建testng.xml
3】testng.xml(文件名随便)中,我们采用 ==> ==> ==> 标签嵌套来完成一个测试套的管理,是测试套在最外层,是测试用例, ==> 是测试类。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<!-- @BeforeSuite -->
<suite name="All Test Suite">
<!-- @BeforeTest -->
<test name="case1">
<classes>
<class name="org.ant.test.testcase.TestConfig"></class>
<class name="org.ant.test.testcase.TestHelloWorld"></class>
</classes>
</test>
<!-- @AfterTest -->
<!-- @BeforeTest -->
<test name="case2">
<classes>
<class name="org.ant.test.testcase.TestConfig"></class>
</classes>
</test>
<!-- @AfterTest -->
</suite>
<!-- @AfrerSuite -->
4】选择testng.xml右键运行,运行结果:
五、配置文件xml常用标签
1】复制testng.xml粘贴为testng1.xml,并写入
<?xml version="1.0" encoding="UTF-8"?>
<suite name="tester">
<test name="case1">
<classes>
<class name="org.ant.test.testcase.TestHelloWorld"/>
<class name="org.ant.test.testcase.TestConfig">
<methods>
<include name="test1" /> <!-- 运行test1()方法-->
<exclude name="test2" /> <!-- 不运行test2()方法-->
</methods>
</class>
</classes>
</test>
<test name="case2">
<packages>
<package name="org.ant.test.testcase" />
</packages>
<groups>
<run>
<exclude name="group1" /> <!-- 不运行组group1的所有方法,或者也可include标签来表示需要行的组-->
</run>
</groups>
</test>
</suite>
2】testng1.xml右键运行,运行结果:
六、参数传递
1、使用@Parameters注解从测试配置xml文件获取参数
1】新建测试类TestParameter
public class TestParameter {
@Test
@Parameters({"param","param2"})
public void printParameters(String param, String param2){
System.out.println("param参数值为:" + param);
System.out.println("param2参数值为:" + param2);
}
2】新建配置xml文件,parameterTest.xml
<?xml version="1.0" encoding="UTF-8"?>
<suite name="parameterTest">
<test name="case1">
<parameter name="param" value="param的值"></parameter>
<parameter name="param2" value="param2的值"></parameter>
<classes>
<class name="org.ant.test.testcase.TestParameter"></class>
</classes>
</test>
</suite>
3】parameterTest.xml右键运行,运行结果:
2、使用@DataProvider传送参数,@Dataprovider可以传递一些比较复杂的参数
1】新建一个测试类TestParameter2
public class TestParameter2 {
@DataProvider(name = "user")
public Object[][] Users() {
return new Object[][]{
{"root", "password"},
{"csdn.com", "zjkl"},
{"python", "java"}
};
}
@Test(dataProvider = "user")
public void verifyUser(String userName,String password){
System.out.println("Username:" + userName + "Password:" + password);
}
}
2】点击运行,结果:
七、测试报告
testng执行结束后,默认测试报告在当前项目文件夹下的test-output文件夹内,index.html是汇总的测试测试报告,用浏览器打开就可以查看了,parameterTest文件夹下是按测试用例生成的报告,old文件夹下为历史报告。
注意:测试报告没有生成的解决办法
1、检查testng的jar包依赖
2、idea没有勾选默认调用报告选项
八、TestNG功能汇总回顾
| 功能 | 实现 |
|---|---|
| 测试注释 | @Test |
| 套件测试 | 标签 |
| 在套件中的所有测试运行之前运行 | @BeforeSuite |
| 在套件中的所有测试运行之后运行 | @AfterSuite |
| 测试之前运行 | @BeforeTest |
| 测试之后运行 | @AfterTest |
| 分组测试 | @Test的group参数 |
| 在调用属于任何这些组的第一个测试方法之前运行 | @BeforeGroups |
| 在调用属于任何这些组的第一个测试方法之后运行 | @AfterGroups |
| 在调用当前类的第一个测试方法之前运行 | @BeforeClass |
| 在调用当前类的第一个测试方法之后运行 | @AfterClass |
| 在每个测试方法之前运行 | @BeforeMethod |
| 在每个测试方法之后运行 | @AfterMethod |
| 预期的异常 | @Test(expectedExceptions = ArithmeticException.class) |
| 超时测试 | @Test(timeout=1000) |
| 参数化测试 | @Parameters或DataProvider |
| 依赖测试 | @Test的dependsOnMethods参数 |