分享一些存货,主要是TestNG的一些用法,分三篇,这是第一篇。
猛戳:第二篇-TestNG进阶
一、TestNG是什么?
TestNG是一个开源的单元测试框架,灵感来源与JUnit和NUnit。
1. 注解
2. 参数化测试
3. 支持依赖测试方法
4. 支持组概念
5. 支持多线程测试
6. 灵活的配置
二、TestNG怎么运行?
1. 通过TestNG配置文件
2. 直接运行有@Test标签的java文件
3. 命令行
三、TestNG的注解
⼀个suite(套件) 由⼀个或多个测试组成。
⼀个test(测试) 由⼀个或多个类组成。
⼀个class(类) 由⼀个或多个⽅法组成。
@BeforeSuite/@AfterSuite:被注释⽅法将在某个测试套件运⾏前/某个测试套件所有测试⽅法运⾏后执⾏
@BeforeTest/@AfterTest:被注释⽅法将在测试运⾏前/某个测试所有测试⽅法运⾏后执⾏
@BeforeClass/@AfterClass:被注释⽅法将在当前类的第⼀个测试⽅法调⽤前/当前类所有测试⽅法运⾏后运⾏
@BeforeMethod/@AfterMethod:被注释⽅法将在每⼀个测试⽅法调⽤前/后运⾏
@BeforeSuite/@AfterSuite/@BeforeTest/@AfterTest可以对不同的测试类⽣效,其他注解只在本类范围内⽣效
执行顺序:
@BeforeSuite->@BeforeTest->@BeforeClass->
{@BeforeMethod->@Test->@AfterMethod}
->@AfterClass->@AfterTest->@AfterSuite
其中{}内的与多少个@Test,就循环执⾏多少次
举个栗子🌰:
//Java文件:
public class TestAnnotation1 {
@BeforeSuite
public void beforeSuite() {
System.out.println("===Suite执⾏之前操作====");
}
@AfterSuite
public void afterSuite() {
System.out.println("===Suite执⾏之后操作==");
}
@BeforeTest
public void beforeTest() {
System.out.println("***TestAnnotation1--Test执⾏之前操作");
}
@AfterTest
public void afterTest() {
System.out.println("===TestAnnotation1--Test执⾏之后操作");
}
@BeforeClass
public void beforeClass() {
System.out.println("****TestAnnotation1--Class执⾏之前操作*");
}
@AfterClass
public void afterClass() {
System.out.println("===TestAnnotation1--Class执⾏之后操作==");
}
@BeforeMethod
public void beforeMethod() {
System.out.println("***TestAnnotation1--Method执⾏之前操作");
}
@AfterMethod
public void afterMethod() {
System.out.println("===TestAnnotation1--Method执⾏之后操作=");
}
@Test
public void test(){}
}
//testng.xml文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestSuite">
<test name="Test1">
<classes>
<class name="com.test.testng.TestAnnotation1"/>
</classes>
</test>
</suite>
四、TestNG的参数化
我们先看一段代码
public class SimpleTest {
@BeforeClass
public void BeforeClass() {
System.out.println("Before Class");
}
@BeforeMethod
public void BeforeMethod() {
System.out.println("Before Method");
}
@Test
public void testAdd() {
Integer sum1 = MathSolution.Add(1, 2);
assertThat("Add 1 + 2 结果错误", sum1, equalTo(3));
}
@Test
public void testAdd2() {
Integer sum2 = MathSolution.Add(null, null);
assertThat("Add null + null 结果错误", sum2, equalTo(null));
}
@Test
public void testAdd3() {
Integer sum3 = MathSolution.Add(Integer.MAX_VALUE,
Integer.MAX_VALUE);
assertThat("Too Big", sum3, equalTo(null));
}
}
这段代码有啥缺点?
被测试数据散落在程序中,维护性差、可读性差、case构造起来繁琐
那我们怎么办呢?当然是参数化了。
TestNG参数化有几种方式:
1.使用@DataProvider
2.xml配置文件
@DataProvider:标记⼀个⽅法⽤于为测试⽅法提供数据。
被注释的⽅法必须返回Object[][](Iterator<Object[]>), 其中每个Object[]可以指派为这个测试⽅法的参数列表。
从DataProvider接收数据,@Test⽅法需要指定dataProvider属性。
//DataProvider栗子
public class DataProviderTest {
@BeforeClass
public void BeforeClass() {
System.out.println("Before Class");
}
@BeforeMethod
public void BeforeMethod() {
System.out.println("Before Method");
}
@DataProvider
public Object[][] paramData() {
return new Object[][] {
{"Add 1 + 2", 1, 2, 3},
{"Add null + null", null, null, null},
{"Add Big", Integer.MAX_VALUE, Integer.MAX_VALUE, null}
};
}
//指定使用哪个DataProvider
@Test(dataProvider="paramData")
public void testDataProvider(String caseDetail, Integer num1, Integer num2, Integer expect) {
Integer sum = MathSolution.Add(num1, num2);
assertThat(caseDetail, expect, equalTo(sum));
}
}
参数化之后代码是不是看起来更加简洁了?我们也可以用文件做为数据源,DB做为数据源。不妨自己动手实验一番吧~
如果再做一个数据源适配器,是不是就更好了?
xml提供参数,在xml中定义parameter,Java文件中使用@Parameter注解来引用参数。下面来看断代码。
//Java文件,引用参数sql
public class ConfDataProviderTest {
private String sql;
@Parameters({"sql"})
@BeforeClass
public void beforeClass(String sql) {
this.sql = sql;
}
@DataProvider
public Iterator<Object[]> confData() throws ClassNotFoundException, SQLException {
DataProvider_byDB dataProvider_byDB = new
DataProvider_byDB("127.0.0.1", "5002", "test_testng", "testng", "testng", sql);
return dataProvider_byDB.getDBData();
}
@Test(dataProvider = "confData")
public void testDBDataProvider(Map<String, String> data) {
Integer num1 = (data.get("num1") == null) ? null : Integer.valueOf(data.get("num1"));
Integer num2 = (data.get("num2") == null) ? null : Integer.valueOf(data.get("num2"));
Integer expect = (data.get("expect") == null) ? null : Integer.valueOf(data.get("expect"));
String caseDetail = data.get("case_detail").toString();
Integer sum = MathSolution.Add(num1, num2);
assertThat(caseDetail, expect, equalTo(sum));
}
}
//xml文件,提供参数sql
<test name="Test3">
<parameter name="sql" value="select * from dataprovider where project_name='Test_TestNG'"/>
<classes>
<class name="com.test.testng.Lesson2DataProvider.DataProviderTest"/>
<class name="com.test.testng.Lesson2DataProvider.DBDataProviderTest"/>
<class name="com.test.testng.Lesson2DataProvider.ExcelDataProviderTest"/>
<class name="com.test.testng.Lesson2DataProvider.ConfDataProviderTest"/>
</classes>
</test>
介绍完@DataProvider注解,不得不提一下另一个跟他很相似的注解@Factory
@Factory是用来创建一个测试类的多个实例,每个实例的属性不同,以执行不同的测试。
@Factory与@DataProvider有啥区别呢?
- DataProvider:为测试用例提供参数,有多少组参数就会执行多少次用例,因此它是一个让测试类实例的某个方法执行多次,但每次执行都使用同一个实例。
- Factory:创建一个测试类的多个实例,每个实例中的所有测试用例都会被执行,因此它是一个测试类被执行多次,每次执行采用的是不同实例。
看个栗子,@Factory:
public class Test1 {
private int count;
public Test1(int count) {
this.count = count;
}
//两个不同实例
@Test
public void test() {
System.out.println("Test1-不同实例地址-" + this);
for (int i = 0; i < count; i++) {
System.out.println("Test1-test-" + i);
}
}
}
//Factory
public class FactoryTest {
@Factory
public Object[] factoryTest1() {
return new Object[]{new Test1(1), new Test1(2)};
}
}
执行结果如下,可以看到是两个不同的实例:
image.png
再看一个DataProvider的栗子:
public class Test2 {
@DataProvider
public Object[][] getData() {
return new Object[][]{
{1},
{2}
};
}
//两个相同实例
@Test(dataProvider = "getData")
public void test(int count) {
System.out.println("Test2-相同实例地址-" + this);
for (int i = 0; i < count; i++) {
System.out.println("Test2-test-" + i);
}
}
}
执行结果如下,可以看到是两个相同的地址:
image.png
感兴趣可以去我的github上下载代码,记得star哦~
https://github.com/bingerlby/testngpro
网友评论