【Java技术指南】「TestNG专题」单元测试框架之TestNG使用教程指南(上)

简介: 【Java技术指南】「TestNG专题」单元测试框架之TestNG使用教程指南(上)

TestNG介绍


TestNG是Java中的一个测试框架, 类似于JUnit 和NUnit, 功能都差不多, 只是功能更加强大,使用也更方便。 详细使用说明请参考官方链接:testng.org/doc/index.h…




TestNG安装


<dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>6.10</version>
      <scope>test</scope>
</dependency>
复制代码


TestNG的优点


  • 漂亮的HTML格式测试报告
  • 支持并发测试
  • 参数化测试更简单
  • 支持输出日志
  • 支持更多功能的注解



编写TestNG测试用例的步骤


  • 使用 Eclipse生成TestNG的测试程序框架
  • 在生成的程序框架中编写测试代码逻辑
  • 根据测试代码逻辑,插入TestNG注解标签
  • 配置Testng.xml文件,设定测试类、测试方法、测试分组的执行信息
  • 执行TestNG的测试程序




TestNG的简单用例


Java直接运行
package com.demo.test.testng;
import org.testng.annotations.Test;
public class NewTest {
  @Test
  public void testFunction() {
      System.out.println("this is new test");
      Assert.assertTrue(true);
  }
}
复制代码



xml方式运行


由于我将xml放置在其他文件夹,不和class放在一个文件夹,所以需要修改xml,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<suite name="Suite" parallel="false">
  <test name="Test">
    <classes>
      <class name="com.demo.test.testng.NewTest"/>
    </classes>
  </test> <!-- Test -->
</suite> <!-- Suite -->
复制代码


TestNG的注解

TestNG支持多种注解,可以进行各种组合,如下进行简单的说明image.png@BeforeSuite > @BeforeTest > @BeforeMethod > @Test > @AfterMethod > @AfterTest > @AfterSuite



如上列表中的@Factory、@Linsteners这两个是不常用的; 前十个注解看起来不太容易区分,顺序不太容易看明白,以如下范例做简单说明,代码


import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
public class NewTest {
  @Test(groups="group1")
  public void test1() {
    System.out.println("test1 from group1");
    Assert.assertTrue(true);
  }
  @Test(groups="group1")
  public void test11() {
    System.out.println("test11 from group1");
    Assert.assertTrue(true);
  }
  @Test(groups="group2")
  public void test2() 
  {
    System.out.println("test2 from group2");
    Assert.assertTrue(true);
  }
  @BeforeTest
  public void beforeTest() 
  {
    System.out.println("beforeTest");
  }
  @AfterTest
  public void afterTest() 
  {
    System.out.println("afterTest");
  }
  @BeforeClass
  public void beforeClass() 
  {
    System.out.println("beforeClass");
  }
  @AfterClass
  public void afterClass() 
  {
    System.out.println("afterClass");
  }
  @BeforeSuite
  public void beforeSuite() 
  {
    System.out.println("beforeSuite");
  }
  @AfterSuite
  public void afterSuite() 
  {
    System.out.println("afterSuite");
  }
  //只对group1有效,即test1和test11
  @BeforeGroups(groups="group1")
  public void beforeGroups() 
  {
    System.out.println("beforeGroups");
  }
  //只对group1有效,即test1和test11
  @AfterGroups(groups="group1")
  public void afterGroups() 
  {
    System.out.println("afterGroups");
  }
  @BeforeMethod
  public void beforeMethod() 
  {
    System.out.println("beforeMethod");
  }
  @AfterMethod
  public void afterMethod() 
  {
    System.out.println("afterMethod");
  }
}
复制代码



运行结果如下:
beforeSuite
beforeTest
beforeClass
beforeGroups
beforeMethod
test1 from group1
afterMethod
beforeMethod
test11 from group1
afterMethod
afterGroups
beforeMethod
test2 from group2
afterMethod
afterClass
afterTest
PASSED: test1
PASSED: test11
PASSED: test2
===============================================
    Default test
    Tests run: 3, Failures: 0, Skips: 0
===============================================
afterSuite
复制代码



如何创建TestNG测试集合?


  • 在自动化测试的执行过程中,通常会产生批量运行多个测试用例的需求,此需求称为运行测试集合(Test Suite)
  • TestNG的测试用例可以是相互独立的,也可以按照特定的顺序来执行(配置TestNG.xml)



如何配置testNG.xml文件?
<suite name = "TestNG Suite">    //自定义的测试集合名称
  <test name = "test1">    //自定义的测试名称
    <classes>    //定义被运行的测试类
      <class name = "cn.gloryroad.FirstTestNGDemo" />    //测试类的路径
      <class name = "cn.gloryroad.NewTest" />
    </classes>
  </test> 
</suite>
复制代码



测试用例的分组(group)


执行组分组配置如下:

<suite name = "TestNG Suite">
  <test name = "Grouping">
    <groups>
      <run>
        <include name = "动物" />
      </run>
    </groups>
    <classes>
      <class name = "cn.gloryroad.Grouping"/>
    </classes>
  </test>
</suite>
复制代码




执行多组分组时配置如下(两种形式都可以):
<suite name = "TestNG Suite">
  <test name = "Grouping">
    <groups>
      <run>
        <include name = "动物" />   //name分组名称
             <include name = "人" />
      </run>
    </groups>
    <classes>
      <class name = "cn.gloryroad.Grouping"/>
    </classes>
  </test>
</suite>
复制代码



依赖测试(dependsOnMethod)


被依赖的方法优先于此方法执行

@Test(dependsOnMethod = {"方法名称"})
复制代码

特定顺序执行测试用例(priority)



按照数字大小顺序优先执行,优先执行1,然后是2…

@Test(priority = 0/1/2/3/4/…)
复制代码



如何跳过某个测试方法(enabled = false)

@Test(priority = 0/1… , enabled = false)
复制代码

执行结束后,在测试报告中显示跳过的测试用例数,例如skip=1


创建测试案例类


  • 创建一个Java测试类 ParameterizedTest1.java.
  • 测试方法parameterTest()添加到测试类。此方法需要一个字符串作为输入参数。
  • 添加注释 @Parameters("myName") 到此方法。该参数将被传递testng.xml,在下一步我们将看到一个值。

创建Java类文件名 ParameterizedTest1.java

import org.testng.annotations.Parameters;
import org.testng.annotations.Test; 
public class ParameterizedTest1 {
      @Test
      @Parameters("myName")
      public void parameterTest(String myName) {
          System.out.println("Parameterized value is : " + myName);
      }
}
复制代码



创建 TESTNG.XML


创建 testng.xml C:\ > TestNG_WORKSPACE 执行测试案例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
  <suite name="Suite1">
      <test name="test1">
      <parameter name="myName" value="manisha"/>
      <classes>
          <class name="ParameterizedTest1" />
          </classes>
      </test>
  </suite>
复制代码

我们还可以定义参数在级别。假设我们已经定义在两个和级别myName,在这种情况下,常规的作用域规则适用。这意味着,任何类里面标签将查看值参数定义在,而testng.xml文件中的类的其余部分将看到定义在中值

编译使用javac的测试用例类。



javac ParameterizedTest1.java
复制代码

现在,运行testng.xml,其中将运行parameterTest方法。TestNG的将试图找到一个命名myName的第一标签的参数,然后,如果它不能找到它,它会搜索包围在的标签。




验证输出。


Parameterized value is : manisha
===============================================
Suite1
Total tests run: 1, Failures: 0, Skips: 0
===============================================
复制代码
数据驱动(@DataProvider)


  • 当你需要通过复杂的参数或参数需要创建从Java(复杂的对象,对象读取属性文件或数据库等..),在这种情况下,可以将参数传递使用数据提供者。数据提供者@DataProvider的批注的方法。
  • 这个注解只有一个字符串属性:它的名字。如果不提供名称,数据提供者的名称会自动默认方法的名称。数据提供者返回一个对象数组。

让我们看看下面的例子使用数据提供者。第一个例子是@DataProvider的使用Vector,String或Integer 作为参数,第二个例子是关于@DataProvider 的使用对象作为参数。


实例 1


在这里 @DataProvider 通过整数和布尔参数。


创建Java类


创建一个java类PrimeNumberChecker.java。这个类检查,如果是素数。

public class PrimeNumberChecker {
      public Boolean validate(final Integer primeNumber) {
          for (int i = 2; i < (primeNumber / 2); i++) {
              if (primeNumber % i == 0) {
                  return false;
               }
          }
          return true;
      }
  }
复制代码
创建测试案例类


  • 创建一个Java测试类 ParamTestWithDataProvider1.java.
  • 定义方法primeNumbers(),其定义为DataProvider 使用注释。此方法返回的对象数组的数组。
  • 测试方法testPrimeNumberChecker()添加到测试类中。此方法需要一个整数和布尔值作为输入参数。这个方法验证,如果传递的参数是一个素数。
  • 添加注释 @Test(dataProvider = "test1") 到此方法。dataProvider的属性被映射到"test1".
创建Java类文件名ParamTestWithDataProvider1.java


import org.testng.Assert;
  import org.testng.annotations.BeforeMethod;
  import org.testng.annotations.DataProvider;
  import org.testng.annotations.Test;
  public class ParamTestWithDataProvider1 {
      private PrimeNumberChecker primeNumberChecker;
      @BeforeMethod
      public void initialize() {
          primeNumberChecker = new PrimeNumberChecker();
      }
      @DataProvider(name = "test1")
      public static Object[][] primeNumbers() {
          return new Object[][] { { 2, true }, { 6, false }, { 19, true },
                { 22, false }, { 23, true } };
      }
      // This test will run 4 times since we have 5 parameters defined
      @Test(dataProvider = "test1")
      public void testPrimeNumberChecker(Integer inputNumber,
          Boolean expectedResult) {
              System.out.println(inputNumber + " " + expectedResult);
              Assert.assertEquals(expectedResult,
              primeNumberChecker.validate(inputNumber));
      }
  }
复制代码
创建 TESTNG.XML
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
  <suite name="Suite1">
      <test name="test1">
      <classes>
          <class name="ParamTestWithDataProvider1" />
          </classes>
      </test>
  </suite>
复制代码
运行testng.xml.
验证输出。
2 true
6 false
19 true
22 false
23 true
===============================================
Suite1
Total tests run: 5, Failures: 0, Skips: 0
===============================================
复制代码



实例 2


在这里,@DataProvider 传递对象作为参数。

创建Java类

创建一个Java类 Bean.java, 对象带有 get/set 方法

public class Bean {
    private String val;
    private int i;
    public Bean(String val, int i){
        this.val=val;
        this.i=i;
    }
    public String getVal() {
    return val;
    }
    public void setVal(String val) {
    this.val = val;
    }
    public int getI() {
    return i;
    }
    public void setI(int i) {
    this.i = i;
    }
}
复制代码



创建测试案例类


  • 创建一个Java测试类 ParamTestWithDataProvider2.java.
  • 定义方法primeNumbers(),其定义为DataProvider使用注释。此方法返回的对象数组的数组。
  • 添加测试类中测试方法TestMethod()。此方法需要对象的bean作为参数。
  • 添加注释 @Test(dataProvider = "test1") 到此方法.  dataProvider 属性被映射到 "test1".

创建Java类文件名 ParamTestWithDataProvider2.java

import org.testng.annotations.DataProvider;
  import org.testng.annotations.Test;
  public class ParamTestWithDataProvider2 {
      @DataProvider(name = "test1")
      public static Object[][] primeNumbers() {
          return new Object[][] { { new Bean("hi I am the bean", 111) } };
      }
      @Test(dataProvider = "test1")
      public void testMethod(Bean myBean) {
          System.out.println(myBean.getVal() + " " + myBean.getI());
      }
  }
复制代码

创建 TESTNG.XML

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
  <suite name="Suite1">
      <test name="test1">
      <classes>
          <class name="ParamTestWithDataProvider2" />
          </classes>
      </test>
  </suite>
复制代码



运行 testng.xml.
hi I am the bean 111
===============================================
Suite1
Total tests run: 1, Failures: 0, Skips: 0
===============================================
复制代码

测试报告中自定义日志(Reporter.log(“输入自定义内容”)),例如:

@Test(groups = {"人"})
  public void student(){
    System.out.println("学生方法被调用");
    Reporter.log("学生方法自定义日志");
  }
复制代码

测试方法使用大全


TestNG预期异常测试


预期异常测试通过在@Test注解后加入预期的Exception来进行添加,范例如下所示:

@Test(expectedExceptions = ArithmeticException.class)
    public void divisionWithException() {
        int i = 1 / 0;
        System.out.println("After division the value of i is :"+ i);
    }
复制代码
运行结果如下:
[RemoteTestNG] detected TestNG version 6.10.0
[TestNG] Running:
  C:\Users\Administrator\AppData\Local\Temp\testng-eclipse--754789457\testng-customsuite.xml
PASSED: divisionWithException
===============================================
    Default test
    Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
Default suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
[TestNG] Time taken by org.testng.reporters.JUnitReportReporter@55d56113: 0 ms
[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@1e127982: 0 ms
[TestNG] Time taken by org.testng.reporters.jq.Main@6e0e048a: 32 ms
[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 0 ms
[TestNG] Time taken by org.testng.reporters.XMLReporter@43814d18: 0 ms
[TestNG] Time taken by org.testng.reporters.EmailableReporter2@6ebc05a6: 0 ms
复制代码




TestNG忽略测试


有时候我们写的用例没准备好,或者该次测试不想运行此用例,那么删掉显然不明智,那么就可以通过注解@Test(enabled = false)来将其忽略掉,此用例就不会运行了,如下范例:

import org.testng.annotations.Test;
public class TestCase1 {
    @Test(enabled=false)
    public void TestNgLearn1() {
        System.out.println("this is TestNG test case1");
    }
    @Test
    public void TestNgLearn2() {
        System.out.println("this is TestNG test case2");
    }
}
复制代码
运行结果:


this is TestNG test case2
PASSED: TestNgLearn2
复制代码

TestNG超时测试


“超时”表示如果单元测试花费的时间超过指定的毫秒数,那么TestNG将会中止它并将其标记为失败。此项常用于性能测试。如下为一个范例:

import org.testng.annotations.Test;
public class TestCase1 {
    @Test(timeOut = 5000) // time in mulliseconds
    public void testThisShouldPass() throws InterruptedException {
        Thread.sleep(4000);
    }
    @Test(timeOut = 1000)
    public void testThisShouldFail() {
        while (true){
            // do nothing
        }
    }
}
复制代码
结果如下:


PASSED: testThisShouldPass
FAILED: testThisShouldFail
org.testng.internal.thread.ThreadTimeoutException: Method com.demo.test.testng.TestCase1.testThisShouldFail() didn't finish within the time-out 1000
  at com.demo.test.testng.TestCase1.testThisShouldFail(TestCase1.java:37)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:498)
  at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104)
  at org.testng.internal.InvokeMethodRunnable.runOne(InvokeMethodRunnable.java:54)
  at org.testng.internal.InvokeMethodRunnable.run(InvokeMethodRunnable.java:44)
  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
  at java.util.concurrent.FutureTask.run(FutureTask.java:266)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
  at java.lang.Thread.run(Thread.java:748)
复制代码





未完待续


后续会进行详细的介绍使用




相关文章
|
14天前
|
测试技术 C# 数据库
C# 单元测试框架 NUnit 一分钟浅谈
【10月更文挑战第17天】单元测试是软件开发中重要的质量保证手段,NUnit 是一个广泛使用的 .NET 单元测试框架。本文从基础到进阶介绍了 NUnit 的使用方法,包括安装、基本用法、参数化测试、异步测试等,并探讨了常见问题和易错点,旨在帮助开发者有效利用单元测试提高代码质量和开发效率。
116 64
|
23天前
|
存储 监控 网络协议
服务器压力测试是一种评估系统在极端条件下的表现和稳定性的技术
【10月更文挑战第11天】服务器压力测试是一种评估系统在极端条件下的表现和稳定性的技术
95 32
|
4天前
|
前端开发 JavaScript 测试技术
前端小白逆袭之路:如何快速掌握前端测试技术,确保代码质量无忧!
【10月更文挑战第30天】前端开发技术迭代迅速,新手如何快速掌握前端测试以确保代码质量?本文将介绍前端测试的基础知识,包括单元测试、集成测试和端到端测试,以及常用的测试工具如Jest、Mocha、Cypress等。通过实践和学习,你也能成为前端测试高手。
15 3
|
6天前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
10 2
|
8天前
|
编解码 安全 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(10-2):保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali——Liinux-Debian:就怕你学成黑客啦!)作者——LJS
保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali以及常见的报错及对应解决方案、常用Kali功能简便化以及详解如何具体实现
|
13天前
|
Java 程序员 测试技术
Java|让 JUnit4 测试类自动注入 logger 和被测 Service
本文介绍如何通过自定义 IDEA 的 JUnit4 Test Class 模板,实现生成测试类时自动注入 logger 和被测 Service。
20 5
|
19天前
|
存储 人工智能 Java
将 Spring AI 与 LLM 结合使用以生成 Java 测试
AIDocumentLibraryChat 项目通过 GitHub URL 为指定的 Java 类生成测试代码,支持 granite-code 和 deepseek-coder-v2 模型。项目包括控制器、服务和配置,能处理源代码解析、依赖加载及测试代码生成,旨在评估 LLM 对开发测试的支持能力。
29 1
|
8天前
|
人工智能 安全 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(4-2):渗透测试行业术语扫盲完结:就怕你学成黑客啦!)作者——LJS
网络空间安全之一个WH的超前沿全栈技术深入学习之路(4-2):渗透测试行业术语扫盲完结:就怕你学成黑客啦!)作者——LJS
|
8天前
|
安全 大数据 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(3-2):渗透测试行业术语扫盲)作者——LJS
网络空间安全之一个WH的超前沿全栈技术深入学习之路(3-2):渗透测试行业术语扫盲)作者——LJS
|
8天前
|
SQL 安全 网络协议
网络空间安全之一个WH的超前沿全栈技术深入学习之路(1-2):渗透测试行业术语扫盲)作者——LJS
网络空间安全之一个WH的超前沿全栈技术深入学习之路(1-2):渗透测试行业术语扫盲)作者——LJS