TestNG单元测试框架比JUnit要更强大,它提供了更多的拓展功能。目前,大部分自动化测试人员开始转向使用TestNG单元测试框架来运行更复杂的自动化测试用例。
TestNG 是一种单元测试框架,由Cedric Beust创建,它借鉴了JUnit和NUnit框架的优秀设计思想,引入更易用和更强大的功能。TestNG是一种开源自动化测试框架,NG就是下一代 的意思(Next Generation)。TestNG的使用和JUnit有些类似,但是它的设计实现比JUnit框架更好,提供了更灵活和更强大的功能。TestNG消 除了一些老式框架的限制,让程序员通过注解、分组、序列和参数化等多种方式组织和执行自动化测试脚本。
2、参数化测试,TestNG 提供了开箱即用的类似特性。通过在 TestNG 的 XML 配置文件中放入参数化数据,就可以对不同的数据集重用同一个测试用例,甚至有可能会得到不同的结果。支持@DataProvider 注释可以方便地把复杂参数类型映射到某个测试方法。
3、支持分组测试
4、支持多线程测试
5、能生成HTML格式的测试报告
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菜单项,代表安装成功。
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的常见测试用例组织结构如下:
在testing.xml中的配置层级结构如下:
运行不同层级的测试用例时,可通过不同注解实现测试前的初始化工作、测试用例执行工作和测试后的清理工作。
注解名称 |
注解含义 |
@BeforeSuite |
注解的方法将只运行一次,运行所有测试前此套件中。 |
@AfterSuite |
注解的方法将只运行一次此套件中的所有测试都运行之后。 |
@BeforeClass |
注解的方法将只运行一次先行先试在当前类中的方法调用。 |
@AfterClass |
注解的方法将只运行一次后已经运行在当前类中的所有测试方法。 |
@BeforeTest |
注解的方法将被运行之前的任何测试方法属于内部类的 |
@AfterTest |
注解的方法将被运行后,所有的测试方法,属于内部类的 |
@BeforeGroups |
组的列表,这种配置方法将之前运行。此方法是保证在运行属于任何这些组第一个测试方法,该方法被调用。 |
@AfterGroups |
组的名单,这种配置方法后,将运行。此方法是保证运行后不久,最后的测试方法,该方法属于任何这些组被调用。 |
@BeforeMethod |
注解的方法将每个测试方法之前运行。 |
@AfterMethod |
被注释的方法将被运行后,每个测试方法。 |
@DataProvider |
标志着一个方法,提供数据的一个测试方法。注解的方法必须返回一个Object[] [],其中每个对象[]的测试方法的参数列表中可以分配。 该@Test 方法,希望从这个DataProvider的接收数据,需要使用一个dataProvider名称等于这个注解的名字。 |
@Factory |
作为一个工厂,返回TestNG的测试类的对象将被用于标记的方法。该方法必须返回Object[]。 |
@Listeners |
定义一个测试类的监听器。 |
@Parameters |
介绍如何将参数传递给@Test方法。 |
@Test |
标记一个类或方法作为测试的一部分。 |
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("在当前测试集合中的所有测试程序运行结束之后执行");
}
}
执行结果为:
控制台输出信息为:
各个含有注解的类的方法如果被调用,均会打印出其对应的注解含义,从执行的结果可以分辨出不同的注解方法会在何时被调用,可以更好地理解注解的执行含义。
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文件,此报告提供更加详细的测试用例执行信息。
通常会产生批量运行多个测试用例的需求,此需求称为运行测试集合(Test Suite)。TestNG的测试用例可以是相互独立的,也可以按照特定的顺序来执行。
通过TestNG.xml的配置,可实现运行多个测试用例的不同组合。
具体操作步骤如下:
1、在TestNGProj工程中,新建一个xml文件,命名为testng.xml。
2、test.xml内容个如下:
其中,suite name是自动以测试集合名称。test name是定义测试名称,classes定义被运行的测试类,此例子定义了之前创建的Annotation和FirstTestNGDemo类。
3、执行testng.xml文件,执行结果如下。
4、以上例子是以class为基本点,此外,还可以以method和package为基本点。
以method为基本点(这里只是格式,FirstTestNGDemo里不存在test1和test2两个方法)
以package为基本点
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的配置如下:
4、运行testng.xml文件,运行结果如下:
5、从运行结果可以看出,标记为“动物”分组测试方法全部被调用。在xml中,把“动物”改为“人”,再次执行测试类程序,则会调用“人”分组中所有测试方法。
6、如果想同时执行两个分组中的所有测试用例,testng.xml修改为:
某些复杂的测试场景需要按照某个特定顺序执行测试用例,以此保证某个测试用例被执行之后才执行其他测试用例,此测试场景运行需求成为依赖测试。通过依赖测试,可在不同测试方法间共享数据和程序状态。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"即可,这种方法比较灵活,修改比较容易,变更顺序不需要修改测试类。
测试中,有时候我们期望某些代码抛出异常。
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提供了2种传递参数的方式。
使代码和测试数据分离,方便维护,但是如果数据量大或者参数比较复杂就不合适了。
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
运行testng.xml,结果如下:
能够提供比较复杂的参数,数据驱动框架,就是基于这种方法。
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() {
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默认情况下,会生产两种类型的测试报告HTML的和XML的。 测试报告位于 "test-output" 目录下。
设置测试报告的内容级别,verbose="2" 标识的就是记录的日志级别,共有0-10的级别,其中0表示无,10表示最详细。
在测试过程中可以通过自定义的方式记录测试脚本的运行信息。例如,记录测试程序的执行步骤信息及测试出错时的异常信息等。日志信息一般使用两种模式进行记录,即高层级和低层级。低层级模式日志会记录所有的测试步骤信息,高层级模式日志只记录测试脚本中的主要时间信息。
自定义日志使用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允许在测试过程中对测试程序变量的中间状态进行断言(Assert)判断,从而辅助判断测试用例的执行是成功还是失败。
TestNG中常用的断言方法有:
具体的用例如下:
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,则断言测试用例执行成功,测试程序会继续执行后续语句,否则当前测试用例会被设定为执行失败,且不再执行后续语句。
测试结果如下