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


    TestNG介绍

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

    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支持多种注解,可以进行各种组合,如下进行简单的说明

    @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:UsersAdministratorAppDataLocalTemp	estng-eclipse--754789457	estng-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)
    

    未完待续

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

    极限就是为了超越而存在的
  • 相关阅读:
    MongoDB 连接
    MongoDB 概念解析
    Linux平台安装MongoDB
    window平台安装MongoDB
    MongoDB 简介
    NoSQL 简介
    Docker有用的资源
    Docker常见仓库Redis
    Docker常见仓库MongoDB
    微信小程序
  • 原文地址:https://www.cnblogs.com/liboware/p/15196384.html
Copyright © 2020-2023  润新知