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)};
  }
}

执行结果如下,可以看到是两个不同的实例:

 

 再看一个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);
    }
  }
}

执行结果如下,可以看到是两个相同的地址:

 

 

 



posted @ 2021-06-05 08:17  陈晓猛  阅读(174)  评论(0编辑  收藏  举报