TestNG系列-TestNG入门

分享一些存货,主要是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做为数据源。不妨自己动手实验一番吧~
如果再做一个数据源适配器,是不是就更好了?

image.png

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

下一篇我们讲TestNG的高级用法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容