单元测试框架——TestNG

        TestNG单元测试框架比JUnit要更强大,它提供了更多的拓展功能。目前,大部分自动化测试人员开始转向使用TestNG单元测试框架来运行更复杂的自动化测试用例。

TestNG的介绍

        TestNG 是一种单元测试框架,由Cedric Beust创建,它借鉴了JUnit和NUnit框架的优秀设计思想,引入更易用和更强大的功能。TestNG是一种开源自动化测试框架,NG就是下一代 的意思(Next Generation)。TestNG的使用和JUnit有些类似,但是它的设计实现比JUnit框架更好,提供了更灵活和更强大的功能。TestNG消 除了一些老式框架的限制,让程序员通过注解、分组、序列和参数化等多种方式组织和执行自动化测试脚本。

TestNG的优点

1、可指定执行顺序, dependsOnMethods 属性来应对测试的依赖性问题。

2、参数化测试,TestNG 提供了开箱即用的类似特性。通过在 TestNG 的 XML 配置文件中放入参数化数据,就可以对不同的数据集重用同一个测试用例,甚至有可能会得到不同的结果。支持@DataProvider 注释可以方便地把复杂参数类型映射到某个测试方法。

3、支持分组测试

4、支持多线程测试

5、能生成HTML格式的测试报告

在eclipse中安装TestNG插件

在eclipse中在线安装TestNG

1、打开Eclipse   Help ->Install New Software ,  在弹出的窗口上单击“Add”按钮。

2、在弹出的对话框中的“Name”输入框中输入“TestNG”,“Location”输入框中输入“http://beust.com/eclipse”,单击“OK”按钮。

                       

4、在弹出的“Install”对话框中,勾选“TestNG”复选框,单击“Next”。


5、一直点击“Next”,在以下页面中,选择“I accept the terms....”,点击“Finish”


6、eclipse开始安装TestNG插件,安装过程中,弹出警告框,单击‘OK’按钮继续安装。

                                   


7、安装完成后,系统提示重启eclipse,单击YES

                            

8、重启后,在工程名称上点击右键,弹出的菜单可以看到TestNG菜单项,代表安装成功。



在eclipse中离线安装TestNG

1、下载TestNG离线安装包,此处提供一个下载地址https://pan.baidu.com/s/1chAaMenZwYRpyK7IaqyK1A

2、将解压后的文件..\eclipse-testng插件\features\org.testng.eclipse_6.8.6.20130607_0745,这个文件夹放到..\eclipse\features下。

3、将解压后的文件..\eclipse-testng插件\plugins\org.testng.eclipse_6.8.6.20130607_0745,这个文件夹放到..\eclipse\plugins下。

4、重启eclipse,安装成功。

5、验证是否安装成功,跟在线安装的验证方法一样。


TestNG注解

        TestNG的常见测试用例组织结构如下:

  • Test Suite由一个或者多个Test组成。
  • Test由一个或者多个测试Class组成。
  • 一个测试Class由一个或者多个测试方法组成。

 在testing.xml中的配置层级结构如下:

<suite>
    <test>
        <classes>
            <method>
            </method>
        </classes>
     </test>
</suite>

        运行不同层级的测试用例时,可通过不同注解实现测试前的初始化工作、测试用例执行工作和测试后的清理工作。

TestNG常用的注解

注解名称

注解含义

@BeforeSuite

注解的方法将只运行一次,运行所有测试前此套件中。

@AfterSuite

注解的方法将只运行一次此套件中的所有测试都运行之后。

@BeforeClass

注解的方法将只运行一次先行先试在当前类中的方法调用。

@AfterClass

注解的方法将只运行一次后已经运行在当前类中的所有测试方法。

@BeforeTest

注解的方法将被运行之前的任何测试方法属于内部类的 <test>标签的运行。

@AfterTest

注解的方法将被运行后,所有的测试方法,属于内部类的<test>标签的运行。

@BeforeGroups

组的列表,这种配置方法将之前运行。此方法是保证在运行属于任何这些组第一个测试方法,该方法被调用。

@AfterGroups

组的名单,这种配置方法后,将运行。此方法是保证运行后不久,最后的测试方法,该方法属于任何这些组被调用。

@BeforeMethod

注解的方法将每个测试方法之前运行。

@AfterMethod

被注释的方法将被运行后,每个测试方法。

@DataProvider

标志着一个方法,提供数据的一个测试方法。注解的方法必须返回一个Object[] [],其中每个对象[]的测试方法的参数列表中可以分配。

该@Test 方法,希望从这个DataProvider的接收数据,需要使用一个dataProvider名称等于这个注解的名字。

@Factory

作为一个工厂,返回TestNG的测试类的对象将被用于标记的方法。该方法必须返回Object[]。

@Listeners

定义一个测试类的监听器。

@Parameters

介绍如何将参数传递给@Test方法。

@Test

标记一个类或方法作为测试的一部分。

TestNG注解使用实例

package cn.om;

import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.AfterSuite;

public class Annotation {
	
	
  @Test
  public void testCase1() {
	  System.out.println("测试用例1被执行");
	  
  }
  
  public void testCase3(){
	  System.out.println("测试用例3被执行");
  }
  
  @Test
  public void testCase2() {
	  System.out.println("测试用例2被执行");
  }
  
  @BeforeMethod
  public void beforeMethod() {
	  System.out.println("在这个测试方法开始运行前执行");
  }

  @AfterMethod
  public void afterMethod() {
	  System.out.println("在这个测试方法开始运行结束执行");
  }

  @BeforeClass
  public void beforeClass() {
	  System.out.println("在当前测试类的第一个测试方法开始调用钱执行");
	  System.out.println();
  }

  @AfterClass
  public void afterClass() {
	  System.out.println();
	  System.out.println("在当前测试类的最后一个测试方法开始调用钱执行");
  }

  @BeforeTest
  public void beforeTest() {
	  System.out.println("在测试类中的Test开始运行前执行");
  }

  @AfterTest
  public void afterTest() {
	  System.out.println("在测试类中的Test运行结束后执行");
  }

  @BeforeSuite
  public void beforeSuite() {
	  System.out.println("在当前测试集合中的所有测试程序开始运行之前执行");
	  System.out.println();
  }

  @AfterSuite
  public void afterSuite() {
	  System.out.println();
	  System.out.println("在当前测试集合中的所有测试程序运行结束之后执行");
  }

}

执行结果为:


控制台输出信息为:


        各个含有注解的类的方法如果被调用,均会打印出其对应的注解含义,从执行的结果可以分辨出不同的注解方法会在何时被调用,可以更好地理解注解的执行含义。

使用TestNG编写WebDriver脚本

1、创建一个工程名为“TestNGProj”,配置好WebDriver相关的JAR包。并且在工程的Configure Build Path界面中,进行“Add Library”操作,添加“TestNG”。

2、新建一个package,命名为cn.om。

3、在这个package上,单击右键,选择“New”——“Other”,在弹出的页面中选择TestNG下的“TestNG class”。在弹出的对话框中,“Source folder”输入框为“/TestNGProj/src”,package name默认为当前包的名字,在“Class name”输入框中输入自定义的测试类名称FitstTestNGDemo,勾选“BeforeMethod”和“AfterMethod”,单击“Finish”。

4、eclipse自动生成如下代码:

5、在生成的代码框架中,编写WebDriver的测试代码。

package cn.om;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;

public class FitstTestNGDemo {

    public WebDriver driver;
    String url = "http://www.baidu.com/";

    @Test
    public void testSearch() {
        driver.get(url);
        WebElement element = driver.findElement(By.id("kw"));
        element.sendKeys("selenium");
        driver.findElement(By.id("su")).click();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println(driver.getTitle().toLowerCase()
                .startsWith("selenium"));

    }

    @BeforeMethod
    public void beforeMethod() {
        // firefox浏览器不是安装在默认路径,要设定当前friefox浏览器的安装路径
        System.setProperty("webdriver.firefox.bin",
                "E:/Mozilla Firefox/firefox.exe");
        driver = new FirefoxDriver();
    }

    @AfterMethod
    public void afterMethod() {
        driver.quit();
    }
}


6、执行这个测试类,执行结果如下

Console执行结果

Result of running class FirstTestNGDemo结果

7、TestNG也会输出HTML格式的测试报告,访问工程目录下的“test-output”目录,打开目录中的“emailable-report.html”文件。

8、打开“test-output”目录中的index.html文件,此报告提供更加详细的测试用例执行信息。



TestNG测试用例特性

TestNG测试集合(使用xml运行测试用例)

        通常会产生批量运行多个测试用例的需求,此需求称为运行测试集合(Test Suite)。TestNG的测试用例可以是相互独立的,也可以按照特定的顺序来执行。

        通过TestNG.xml的配置,可实现运行多个测试用例的不同组合。

        具体操作步骤如下:

        1、在TestNGProj工程中,新建一个xml文件,命名为testng.xml。

        2、test.xml内容个如下:

<suite name="TestNGSuite">
    <test name="test1">
        <classes>
            <class name="cn.om.FitstTestNGDemo" />
            <class name="cn.om.Annotation" />
        </classes>
    </test>
</suite>


        其中,suite name是自动以测试集合名称。test name是定义测试名称,classes定义被运行的测试类,此例子定义了之前创建的Annotation和FirstTestNGDemo类。

        3、执行testng.xml文件,执行结果如下。

                


        4、以上例子是以class为基本点,此外,还可以以method和package为基本点。

        以method为基本点(这里只是格式,FirstTestNGDemo里不存在test1和test2两个方法)

<suite name="TestNGSuite">
	<test name="test1">
		<classes>
			<class name="cn.om.FitstTestNGDemo" />
			<method>
				<include name="test1" />
				<include name ="test2"/>
			</method>
		</classes>
	</test>
</suite>

        以package为基本点

<suite name="TestNGSuite">
	<test name="test1">
		<packages>
			<package name="cn.om" />
		</packages>
	</test>
</suite>

TestNG测试用例的分组

       TestNG使用group关键字进行分组,用来执行多个Test的测试用例。使用此方式可将测试用例进行任意分组,并根据测试需求执行不同分组的测试用例。

        具体操作如下:

        1、在当前工程内,创建一个名为Grouping的测试类。

        2、编写两个类方法归属给命名为“人”的测试用例分组,两个类方法归属给命名为“动物”的测试用例分组,一个类方法既归属于“人”的测试用例又归属“动物”的测试用例分组。使用groups={"分组名"}的方式设定测试方法与分组的归属关系。

package cn.om;

import org.testng.annotations.Test;

public class Grouping {
	@Test (groups ={"人"})
	public void student(){
       System.out.println("学生方法被调用");
	}
	
	@Test (groups ={"人"})
	public void teacher(){
       System.out.println("老师方法被调用");
	}
	
	
	@Test (groups ={"动物"})
	public void cat(){
       System.out.println("小猫方法被调用");
	}
	
	@Test (groups ={"动物"})
	public void dog(){
       System.out.println("小狗方法被调用");
	}
	
	@Test (groups ={"人","动物"})
	public void feeder(){
       System.out.println("饲养员方法被调用");
	}
}

        3、tesng.xml的配置如下:

<suite name="TestNGSuite">
	<test name="test1">
		<groups>
			<run>
				<include name="动物"></include>
			</run>
		</groups>
		<classes>
			<class name="cn.om.Grouping" />
		</classes>
	</test>
</suite>

        4、运行testng.xml文件,运行结果如下:

        5、从运行结果可以看出,标记为“动物”分组测试方法全部被调用。在xml中,把“动物”改为“人”,再次执行测试类程序,则会调用“人”分组中所有测试方法。

        6、如果想同时执行两个分组中的所有测试用例,testng.xml修改为:

<suite name="TestNGSuite">
	<test name="test1">
		<groups>
			<define name="All">
				<include name="人" />
				<include name="动物" />
			</define>
			<run>
				<include name="All"></include>
			</run>
		</groups>
		<classes>
			<class name="cn.om.Grouping" />
		</classes>
	</test>
</suite>

TestNG依赖测试

       某些复杂的测试场景需要按照某个特定顺序执行测试用例,以此保证某个测试用例被执行之后才执行其他测试用例,此测试场景运行需求成为依赖测试。通过依赖测试,可在不同测试方法间共享数据和程序状态。TestNG支持依赖测试,使用dependsOnMethods参数来实现。

        具体例子如下:

package cn.om;

import org.testng.annotations.Test;

public class DependentTest {

	@Test (dependsOnMethods={"OpenBrowser"},enabled=false)
	public void SignIn(){
		System.out.println("SignIn方法被调用");
	}
	
	@Test 
	public void OpenBrowser(){
		System.out.println("OpenBrowser方法被调用");
	}
	
	@Test (dependsOnMethods={"SignIn"})
	public void LogOut(){
		System.out.println("LogOut方法被调用");
	}
}
	

        执行结果如下:

        

跳过某个测试方法

       想要跳过某个测试方法,使用参数enabled=false。以上面依赖测试的代码作为例子,在SignIn方法上加上参数。

       

        再次运行,发现运行结果报错。报错原因是因为LogOut方法无法找到需要依赖的方法SignIn,因为SignIn被设为enabled=false。


按特定顺序执行测试用例

        使用参数priority可实现按照特定顺序执行测试用例。具体有两种方法可以实现:

        1、直接在测试类中的方法中定义顺序,如下所示:

package cn.om;

import org.testng.annotations.Test;

public class SequenceTest {
  
	@Test(priority=2)
  public void test3() {
	  System.out.println("test3方法被调用");
  }
	@Test(priority=3)
	  public void test4() {
		  System.out.println("test4方法被调用");
	  }
	
	@Test(priority=0)
	public void test1() {
		  System.out.println("test1方法被调用");
	  }
	
	@Test(priority=1)
	  public void test2() {
		  System.out.println("test2方法被调用");
	  }
}

        执行结果如下:

        2、在xml文件中定义测试方法的执行顺序,添加preserve-order="true"即可,这种方法比较灵活,修改比较容易,变更顺序不需要修改测试类。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
    <test name="test12" preserve-order="true">
        <classes>
            <class name="cn.om.SequenceTest">
                <methods>
                    <include name="test1" />
                    <include name="test2" />
                    <include name="test3" />
                </methods>
            </class>
        </classes>
    </test>
</suite>

TestNG异常测试

        测试中,有时候我们期望某些代码抛出异常。

        TestNG通过@Test(expectedExceptions)  来判断期待的异常, 并且判断Error Message。

package cn.om;

import org.testng.annotations.Test;

public class ExceptionTest {

	@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "NullPoint")
	public void testException() {
		throw new IllegalArgumentException("NullPoint");
	}
}

        执行后,可以捕捉到预期的异常,该实例成功运行。


TestNG参数化测试

        软件测试中,经常需要测试大量的数据集。 测试代码的逻辑完全一样,只是测试的参数不一样。  这样我们就需要一种 “传递测试参数的机制”。 避免写重复的测试代码

        TestNG提供了2种传递参数的方式。

第一种: testng.xml 方式

        使代码和测试数据分离,方便维护,但是如果数据量大或者参数比较复杂就不合适了。

package cn.om;

import org.testng.annotations.Parameters;
import org.testng.annotations.Test;


public class ParameterizedTest1 {
	@Test
	@Parameters("parame1")
	public void ParaTest(String parame1) {
		System.out.println("This is " + parame1);
	}
}

testng.xml

<suite name="TestNGSuite">
	 <parameter name="parame1" value="Tank" />
        <parameter name="parame1" value="Xiao" />
    <test name="parame12">
        <classes>
            <class name="cn.om.ParameterizedTest1" />
        </classes>
    </test>
</suite>

运行testng.xml,结果如下:

第二种:@DataProvider

        能够提供比较复杂的参数,数据驱动框架,就是基于这种方法。

package cn.gloryroad.DataProvider;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class TestDataDrivenByCSVFile {

    private static WebDriver driver;
    String url = "http://www.sogou.com/";

    @DataProvider(name = "testDate")
    public static Object[][] word() throws IOException {
        return new Object[][] { { "searchWord1", "searchWord2", "searchResult" } };
    }

    @Test(dataProvider = "testDate")
    public void testDataDrivenByCSVFile(String searchWord1, String searchWord2,
            String searchResult) {
        driver.get(url);
        driver.findElement(By.id("query")).sendKeys(
                searchWord1 + "" + searchWord2);
        driver.findElement(By.id("stb")).click();
        new WebDriverWait(driver, 10).until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver arg0) {
                // TODO Auto-generated method stub
                return driver.getTitle().toLowerCase().startsWith("ztree");
            }
        });

        System.out.println((String) driver.findElement(By.id("s_footer"))
                .getText());

        Assert.assertTrue(driver.getPageSource().contains(searchResult));
    }

    @BeforeMethod
    public void beforeMethod() {
        System.setProperty("webdriver.firefox.bin",
                "D:/Mozilla Firefox/firefox.exe");
        driver = new FirefoxDriver();

    }

    @AfterMethod
    public void afterMethod() {
        driver.quit();
    }

}

TestNG测试报告

TestNG测试结果报告

        测试报告是测试非常重要的部分。TestNG默认情况下,会生产两种类型的测试报告HTML的和XML的。 测试报告位于 "test-output" 目录下。


日志级别

        设置测试报告的内容级别,verbose="2" 标识的就是记录的日志级别,共有0-10的级别,其中0表示无,10表示最详细。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
    <test name="test12" verbose="2">
        <classes>
            <class name="TankLearn2.Learn.TestNGLearn1" />
        </classes>
    </test>
</suite>

自定义日志

       在测试过程中可以通过自定义的方式记录测试脚本的运行信息。例如,记录测试程序的执行步骤信息及测试出错时的异常信息等。日志信息一般使用两种模式进行记录,即高层级和低层级。低层级模式日志会记录所有的测试步骤信息,高层级模式日志只记录测试脚本中的主要时间信息。

        自定义日志使用Reporter.log()进行输出。

package cn.om;

import org.testng.Reporter;
import org.testng.annotations.Test;

public class TestngReporter {
  @Test
  public void OpenBrowser() {
	  System.out.println("OpenBrowser方法被调用!");
	  Reporter.log("调用打开浏览器的方法!");
  }
  
  @Test
  public void SignIn(){
	  System.out.println("SignIn方法被调用!");
	  Reporter.log("调用登录的方法!");
  }
  
  @Test
  public void LogOut(){
	  System.out.println("LogOut方法被调用!");
	  Reporter.log("调用退出的方法!");
  }
}

运行结果,可以在报告中的Report Log信息,看到打印的信息



TestNG断言

       TestNG允许在测试过程中对测试程序变量的中间状态进行断言(Assert)判断,从而辅助判断测试用例的执行是成功还是失败。

    TestNG中常用的断言方法有:

  • assertTrue:判断是否为True。
  • assertFalse:判断是否为false。
  • assertSame:判断引用地址是否相同。
  • assertNotSame:判断引用地址是否不相同。
  • assertNull:判断是否为null。
  • assertNotNull:判断是否不为null。
  • assertEquals:判断是否相等,Object类型的对象需要实现haseCode及equals方法。
  • assertNotEquals:判断是否不相等。
  • assertEqualsNoOrder:判断忽略顺序是否相等。

 具体的用例如下:

package cn.om;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;

public class FitstTestNGDemo {

	public WebDriver driver;
	String url = "http://www.baidu.com/";

	@Test
	public void testSearch() {
		driver.get(url);
		WebElement element = driver.findElement(By.id("kw"));
		/*使用Assert类的assertTrue方法断言搜索输入框是否在页面显示  
	       * isDisplayed方法根据页面元素的显示状态返回判断值,在页面显示则返回true,不显示则返回false  
	       */  
	      Assert.assertTrue(element.isDisplayed());  
		element.sendKeys("selenium");
		driver.findElement(By.id("su")).click();

		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(driver.getTitle().toLowerCase()
				.startsWith("selenium"));

	}

	@BeforeMethod
	public void beforeMethod() {
		// firefox浏览器不是安装在默认路径,要设定当前friefox浏览器的安装路径
		System.setProperty("webdriver.firefox.bin",
				"E:/Mozilla Firefox/firefox.exe");
		driver = new FirefoxDriver();
	}

	@AfterMethod
	public void afterMethod() {
		driver.quit();
	}
}

       element.isDisplayed()用来判断输入框是否显示在了百度的首页上,若显示则此函数返回值为true,若无显示则返回值为false。Assert.assertTrue(element.isDisplayed()); 用来判断element.isDisplayed()函数返回值是否为true。如果是true,则断言测试用例执行成功,测试程序会继续执行后续语句,否则当前测试用例会被设定为执行失败,且不再执行后续语句。

测试结果如下




猜你喜欢

转载自blog.csdn.net/vikeyyyy/article/details/79986353