大部分参考 TestNG学习链接 的文章,本文为个人笔记记录以及补充。
Java中的开源自动化测试框架,其灵感来自JUnit和NUnit,涵盖了JUnit4整个核心的功能,但引入了一些新的功能,使其功能更强大,使用更方便。
JUnit是ava语言的单元测试框架。Junit详解
灯泡:串起来的线 = Selenium编写的测试用例:JUnit管理用例
1 使用教程
1.1 创建 Maven 项目
1.2 pom.xml 引入依赖
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
</dependency>
</dependencies>
1.3 创建待测试类
public class Test_01 {
public static void main (String[] args) {
System.out.println("我是待测试组");
}
}
- 点击选中刚刚创建的类名,按Alt+Entet键,创建单元测试类
- 勾选三个选项
- 生成代码结构如下
- 添加打印语句测试效果
2 TestNG 知识点
2.1 注释
注释 | 描述 | 运行次数 | 运行顺序 |
---|---|---|---|
@BeforeSuite | 所有测试方法运行之前 | 1 | 1 |
@BeforeTest | Test标签内的所有测试方法 | 1 | 2 |
@BeforeClass | 调用当前类的第一个测试方法之前 | 1 | 3 |
@BeforeGroups | 在组列表运行之前运行 | 取决于组列表个数 | 4 |
@BeforeMethod | 当前类中的每个测试方法之前 | 取决于测试方法个数 | 5 |
—— | 测试方法 | —— | 6 |
@AfterMethod | 当前类中的每个测试方法之后 | 取决于测试方法个数 | 7 |
@AfterGroups | 在组列表运行之前运行 | 取决于组列表个数 | 8 |
@AfterClass | 调用当前类的第一个测试方法之后 | 1 | 9 |
@AfterTest | Test标签内的所有测试方法 | 1 | 10 |
@AfterSuite | 所有测试运行之后运行 | 1 | 11 |
其中,组列表结构运行顺序如下
2.2 断言
1. 硬断言
- 硬断言(Assert类):提供了一系列静态方法,用于测试实际值与期望值是否相符。如果断言失败,即实际值与期望值不匹配,TestNG 会抛出异常并停止执行后续的代码。
1、assertEqual (actual value,expected value )
断言两个值相等。
2、assertTrue(boolean condition)
断言一个条件为真;
3、assertFalse(boolean condition)
断言一个条件为假;
4、assertNotNull(java.lang.Object object)
断言一个对象不为空(null);
5、assertNull(java.lang.Object object)
断言一个对象为空(null);
6、assertSame(java.lang.Object expected, java.lang.Object actual)
断言两个对象引用相同的对象;
7、assertNotSame(java.lang.Object unexpected, java.lang.Object actual)
断言两个对象不是引用同一个对象;
8、assertArrayEquals(expectedArray, resultArray)
断言预期数组和结果数组相等。
- 简单例子
@Test
public void testAssert () throws Exception {
Assert.assertEquals(4, 2 * 2);
System.out.println("通过");
Assert.assertEquals(5, 1+9);
}
运行结果
2. 软断言
- 软断言(SoftAssert类):软断言是TestNG提供的一种更灵活的断言方式,它允许在断言失败后继续执行测试。SoftAssert类允许开发者创建实例对象,并通过该对象调用相关的方法进行断言。这种机制适用于那些可以容忍一定错误率的测试场景,例如在测试大量数据时,部分测试用例失败不会影响整个测试套件的继续执行。
- SoftAssert.java,软断言需要创建实例对象,才能调用相关实例方法进行软断言
- assertAll()一定要放在该测试类的最后一个断言后面
@Test
public void testSoftAssert(){
//实例化SoftAssert
SoftAssert assertion = new SoftAssert();
assertion.assertEquals(5, 6,"我俩不是一样大");
//这个必须放到最后,没什么可说的
assertion.assertAll(); }
}
2.3 参数化测试
1. XML传参
- 测试方法代码
public class 传参类名 {
@Test(enabled=true)
@Parameters({"param1", "param2"})
public void A方法(String param1, int param2) {
// 代码块
Assert.assertFalse(false);
}
}
- XML配置
<?xml version="1.0" encoding="UTF-8"?>
<suite name="Suite" parallel="false">
<test name="Test">
<parameter name="param1" value="1011111" />
<parameter name="param2" value="10" />
<classes>
<class name="传参类名地址"/>
</classes>
</test>
</suite>
2. 使用@DataProvider
传递参数
- 测试方法
public class 传参类名 {
@DataProvider(name = "参数提供")
public Object[][] provideData() {
return new Object[][] { { 10, 20 }, { 100, 110 }, { 200, 210 } };
}
@Test(dataProvider = "参数提供")
public void TestNgLearn1(int param1, int param2) {
// 代码块
Assert.assertFalse(false);
}
}
2.4 常用的方法属性
以下不是完整类,只是各个属性的汇总(作用级别可能是类/方法体等等)
// 整个类之前添为组
@Test(groups= "组名")
public class 类名 {
}
// 方法前添为组
@Test(groups="组名")
public void 测试方法名() {
// 测试方法
}
// 在指定组名前运行的方法
@BeforeGroups(groups="组名")
public void 测试方法名() {
// 代码块
}
// 忽略测试
@Test(enabled=false)
public void 测试方法名() {
// 代码块
}
// 超时测试
@Test(timeOut = 5000)
public void testThisShouldPass() throws InterruptedException {
Thread.sleep(4000);
}
// 异常测试
@Test(expectedExceptions = ArithmeticException.class)
public void divisionWithException() {
int i = 1 / 0;
System.out.println("After division the value of i is :"+ i);
}
// 依赖测试
@Test(enabled=true)
public void A方法() {
// 代码块
Assert.assertFalse(true);// 硬断言为假,则此方法为FALSE了导致不能被其他方法依赖
}
@Test(dependsOnMethods= {"A方法"})
public void B方法() {
// 代码块
// 结果为不可依赖
}
3 综合例子
3.1 测试类内运行
- 完整代码如下
import org.testng.Assert;
import org.testng.annotations.*;
public class newTest {
@Test(groups="第一组")
public void test01() {
System.out.println("第一组测试方法test01");
Assert.assertTrue(true); // 硬断言
}
@Test(groups="第一组")
public void test02() {
System.out.println("第一组测试方法test02");
Assert.assertTrue(true);
}
@Test(groups="第二组")
public void test2()
{
System.out.println("第二组测试方法test2");
Assert.assertTrue(true);
}
@BeforeTest
public void beforeTest()
{
System.out.println("0_beforeTest");
}
@AfterTest
public void afterTest()
{
System.out.println("1_afterTest");
}
@BeforeClass
public void beforeClass()
{
System.out.println("0_beforeClass");
}
@AfterClass
public void afterClass()
{
System.out.println("1_afterClass");
}
@BeforeSuite
public void beforeSuite()
{
System.out.println("0_beforeSuite");
}
@AfterSuite
public void afterSuite()
{
System.out.println("1_afterSuite");
}
//只对第一组有效,即test01和test02
@BeforeGroups(groups="第一组")
public void beforeGroups()
{
System.out.println();
System.out.println("000_beforeGroups");
}
//只对第一组有效,即test01和test02
@AfterGroups(groups="第一组")
public void afterGroups()
{
System.out.println("111_afterGroups");
System.out.println();
}
@BeforeMethod
public void beforeMethod()
{
System.out.println("00_beforeMethod");
}
@AfterMethod
public void afterMethod()
{
System.out.println("11_afterMethod");
}
}
- 运行结果如下
3.2 XML方式运行
模板结构(参考理解)
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="套件名称" verbose="运行级别" >
<test name="测试用例名A">
<classes>
<class name="类名1"/>
</classes>
</test>
<!-- 选中所有包 -->
<test name = "allTestsInAPackage" >
<packages>
<package name = "whole.path.to.package.*" />
</packages>
</test>
<!-- 选择一个包的部分组 -->
<test name = "测试用例名X" >
<groups>
<run>
<include name = "includedGroup" />
</run>
</groups>
<packages>
<package name = "whole.path.to.package.*" />
</packages>
</test>
<!-- 排除一个包的部分组 -->
<test name = "测试用例名X" >
<groups>
<run>
<exclude name = "includedGroup" />
</run>
</groups>
<packages>
<package name = "whole.path.to.package.*" />
</packages>
</test>
<!-- 选中类的某个用例 -->
<test name = "测试用例名X" >
<classes>
<class name="类路径" >
<methods>
<include name = "方法A" />
<include name = "方法B" />
</methods>
</class>
</classes>
</test>
</suite>
- 标签说明
<suite> 套件,根标签,通常由几个<test组成>
属性:
name 套件的名称,必须属性;
verbose 运行的级别或详细程度,,从0开始到10,其中10为最详细;
parallel 是否运行多线程来运行这个套件,默认为none;
thread-count 如果启用多线程,用于指定开户的线程数(parallel参数非none时);
1)methods:方法层级,测试用例级别的多线程。
2)tests:每个<test>标签都将处于一个单独的线程中(包含不是线程安全的所有类分组)
3)classes:类级别并发;
4)instances:实例级别,同一实例中的所有方法,
annotations 在测试中使用的注释类型;
time-out 使用的默认超时时间;
--------------------------分割线--------------------------
<test> 测试用例,name为必须属性;
<classes> 用例中包含的类,子标签为<class>;
<class> 测试类,name为必须属性;
<packages> 用例中包含的包,包中所有的方法都会执行,子标签为<package>;
<package> 测试包,name为必须属性;
<methods> 指定测试类中包含或排除的方法,子类为<include>,<exclude>;
<include> 指定需要测试的方法,name为必须属性;
<exclude> 指定类中不需要测试的方法,name为必须属性;
<groups> 指定测试用例中要运行或排除运行的分组,子标签为<run>,<run>下包含<include>,<exclude>标签,<include>,<exclude>的name指定运行、不运行的分组;
<test name = "aFewTestsFromAClass" >
<classes>
<class name="whole.path.to.package.className" >
<methods>
<include name = "firstMethod" />
<include name = "secondMethod" />
<include name = "thirdMethod" />
</methods>
</class>
</classes>
</test>
<test name = "测试名" >
<groups>
<run>
<include name = "includedGroup" />
</run>
</groups>
<packages>
<package name = "whole.path.to.package.*" />
</packages>
</test>
还是以前面的测试为例:
-
右键项目,创建XML文件,直接输入
testng.xml
(博主一时没找着能直接创建xml格式的选项,于是直接创建普通文件,加上.xml
限定名也一样)
-
代码如下
- 技巧:在输入要测试的用例类名时,IDEA会自动提示,直接选中目标类就好。
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite" parallel="none">
<test name="Test">
<classes>
<class name="newTest"/>
</classes>
</test>
<test name="Test2">
<classes>
<class name="Test_01Test"/>
</classes>
</test>
</suite>
- 右键点击运行即可
4 美化输出结果
- 编辑运行方式
- 美化后的输出结果文件位置
- 浏览器打开效果