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,则断言测试用例执行成功,测试程序会继续执行后续语句,否则当前测试用例会被设定为执行失败,且不再执行后续语句。
测试结果如下