UI自动化测试(六)TestNG操作详解
在编写TestNG代码的时候,若没有下载TestNG的jar包的话,代码会出错,下载jar包方法见该链接中java+selenium环境搭建的第二步即可:http://www.cnblogs.com/hong-fithing/p/7622215.html
运行测试步骤方法有如下两种:
1、 直接在Eclipse运行testNG的测试用例, 在代码编辑区域鼠标右键, 选择Run as ->testNG Test
2、 在工程的根目录下, 建立testng.xml文件, 并在文件中输入配置内容:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" > 3 <suite name="suite1"> 4 <test name="test1"> 5 <classes> 6 <class name="com.ui.day4.CalcTest" /> 7 <class name="com.testng.demo_1" /> 8 </classes> 9 </test> 10 </suite>
然后在工程中的testNG.xml上方鼠标右键单击, 在弹出的菜单中选择Run as ->Test Suite即可运行测试用例,suite代表一个XML文件。 它可以包含一个或多个测试, 并被定义由<suite>标记标签<test>代表一个测试, 并可以包含一个或多个TestNG的类<class>的标签代表一个TestNG的类是一个Java类,它包含至少一个TestNG的注解。它可以包含一个或多个测试方法。
执行结果查看方式:
1、 在Console可以查看测试结果
2、 testNG的Results可以查看
3、 testNG的Html格式测试报告, 该测试报告存在与工程目录下的“test-output”目录下,emailable-report.html和index.html。
TestNG常用注解annotation
注解 | 描述 |
@BeforeSuite | 被注释的方法将在所有测试运行前运行(相当于前置条件) |
@AfterSuite |
被注释的方法将在所有测试运行后运行比如关闭浏览器(使执行其他用例时处于初始状态) |
@BeforeTest | 被注释的方法将在测试运行前运行 |
@AfterTest | 被注释的方法将在测试运行后运行 |
@BeforeGroups |
被配置的方法将在列表中的gourp前运行。这个方法保证在第一个属于这些组的测试方法调用 前立即执行 |
@AfterGroups |
被配置的方法将在列表中的gourp后运行。这个方法保证在最后一个属于这些组的测试方法调 用后立即执行 |
@BeforeClass | 被注释的方法将在当前类的第一个测试方法调用前运行 |
@AfterClass | 被注释的方法将在当前类的所有测试方法调用后运行 |
@BeforeMethod | 被注释的方法将在每一个测试方法调用前运行 |
@AfterMethod | 被注释的方法将在每一个测试方法调用后运行 |
@DataProvider |
标记一个方法用于为测试方法提供数据。 被注释的方法必须返回Object[][],其中每个Object[] 可以指派为这个测试方法的参数列表。从这个DataProvider接收数@Test方法需要使用一个和 当前注释相同名称的dataProvider名称 |
@Factory |
标记方法作为一个返回对象的工厂, 这些对象将被TestNG用于作为测试类。这个方法必须返回 Object[] |
@Listeners | 定义一个测试类的监听器 |
@Parameters | 描述如何传递参数给@Test方法 |
@Test | 标记一个类或方法作为测试的一部分 |
备注:
Before开头的注解一般用于初始化环境、 准备测试环境
after开头的注解一般用于执行测试的环境清理工作
DataProvider一般用作参数化用的, 属于数据驱动自动化(即不同的测试数据测试相同的测试逻辑)
Listeners 自定义日志或者监控一些testNG用例执行成功或者失败的时候做些特别的事情
Parameters可以把xml文件定义的参数传递到测试程序或者测试类中来使用
1 public class yihuqingjiu_test_demo { 2 3 @Test 4 public void testCase1() { 5 System.out.println("in test case 1"); 6 } 7 @Test 8 public void testCase2() { 9 System.out.println("in test case 2"); 10 } 11 @BeforeMethod 12 public void beforeMethod() { 13 System.out.println("in beforeMethod"); 14 } 15 @AfterMethod 16 public void afterMethod() { 17 System.out.println("in afterMethod"); 18 } 19 @BeforeClass 20 public void beforeClass() { 21 System.out.println("in beforeClass"); 22 } 23 @AfterClass 24 public void afterClass() { 25 System.out.println("in afterClass"); 26 } 27 @BeforeTest 28 public void beforeTest() { 29 System.out.println("in beforeTest"); 30 } 31 @AfterTest 32 public void afterTest() { 33 System.out.println("in afterTest"); 34 } 35 @BeforeSuite 36 public void beforeSuite() { 37 System.out.println("in beforeSuite"); 38 } 39 @AfterSuite 40 public void afterSuite() { 41 System.out.println("in afterSuite"); 42 } 43 44 }
运行结果:
in beforeSuite
in beforeTest
in beforeClass
in beforeMethod
in test case 1
in afterMethod
in beforeMethod
in test case 2
in afterMethod
in afterClass
in afterTest
首先beforeSuite()方法执行一次。
最后afterSuite的()方法执行一次。
其次方法 beforeTest(), beforeClass(), afterClass() 和afterTest() 方法各执行一次。
beforeMethod()方法在执行每个测试用例之前执行一次。
afterMethod()方法在执行每个测试用例之后执行一次。
TestNG测试套件
测试套件是为了测试软件程序的行为或一系列行为, 是一个集合。 在TestNG中, 不能在测试源代码中引入测试集合, 但可以用testng.xml文件来进行测试套件的配置。
Testng.xml文件节点属性
suite常用属性介绍 | |
注解 | 描述 |
@name | suite的名称, 必须参数 |
@verbose | 命令行信息打印等级, 不会影响测试报告输出内容; 可选值(1|2|3|4|5) |
@parallel |
是否多线程并发运行测试; 可选值(false | methods | tests | classes |instances)默认 "false" |
@thread-count | 当为并发执行时的线程池数量, 默认为"5" |
@annotations | 获取注解的位置, 如果为"javadoc", 则使用javadoc注解, 否则使用jdk注解 |
junit | 是否以Junit模式运行, 可选值(true | false), 默认"false" |
@time-out | 为具体执行单元设定一个超时时间, 具体参照parallel的执行单元设置; 单位为毫秒 |
test常用属性说明 | |
注解 | 描述 |
@name | test的名字, 必选参数; 测试报告中会有体现 |
@verbose | 命令行信息打印等级, 不会影响测试报告输出内容; 可选值(1|2|3|4|5) |
@parallel |
是否多线程并发运行测试; 可选值(false | methods | tests | classes |instances)默认 "false" |
@thread-count | 当为并发执行时的线程池数量, 默认为"5" |
@annotations | 获取注解的位置, 如果为"javadoc", 则使用javadoc注解, 否则使用jdk5注解 |
@time-out | 为具体执行单元设定一个超时时间, 具体参照parallel的执行单元设置; 单位为毫秒 |
@enabled | 设置当前test是否生效, 可选值(true | false), 默认"true" |
testng.xml中有<suite>根标签。 它描述了一个测试套件, <suite>由一个或多个<test>区段组成, 如下testng.xml文件:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > 3 <suite name="Suite1"> 4 <test name="exampletest1"> 5 <classes> 6 <class name="com.ui.day1.test1" /> 7 </classes> 8 </test> 9 <test name="exampletest2"> 10 <class name="com.ui.day2.test2"> 11 <methods> 12 <include name="test01"></include> 13 </methods> 14 </class> 15 </test> 16 </suite>
TestNG忽略测试
当测试用例还没准备好,可以给测试用例加上@Test(enable =false),来禁用此测试用例。
代码实现:
@Test(enabled = false) public void add(){ Assert.assertEquals(a.add(5, 6), 11); }
TestNG分组测试
顾名思义,是将不同的用例分组,然后再testng.xml文件中配置信息,而执行相应组的用例,代码实现如下,仅供参考:
1 package com.ui.day4; 2 3 import org.testng.Assert; 4 import org.testng.annotations.BeforeSuite; 5 import org.testng.annotations.Test; 6 7 public class yihuqingjiu_test_group { 8 ca a; 9 @BeforeSuite(groups = {"冒烟","回归"}) 10 public void reday() { 11 a = new ca(); 12 } 13 @Test(groups = "冒烟") 14 public void add() { 15 Assert.assertEquals(a.add(5, 6), 11); 16 } 17 @Test(groups = "冒烟") 18 public void min() { 19 Assert.assertEquals(a.minus(6, 5), 1); 20 } 21 @Test(groups = "冒烟") 22 public void cheng() { 23 Assert.assertEquals(a.cheng(6, 5), 30); 24 } 25 @Test(groups = "回归") 26 public void cheng1() { 27 Assert.assertEquals(a.cheng(6, 5), 30); 28 } 29 @Test(groups = "回归") 30 public void chu() { 31 Assert.assertEquals(a.chu(5, 5), 1); 32 } 33 }
testng.xml文件配置如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > 3 <suite name="Suite1" verbose="3"> 4 <test name="test_one"> 5 <groups> 6 <run> 7 <include name="回归" /> 8 </run> 9 </groups> 10 <classes> 11 <class name="com.ui.day4.test_group"></class> 12 </classes> 13 </test> 14 </suite>
TestNG依赖测试
按顺序来调用测试用例,那么测试用例之间就存在依赖关系,TestNG支持测试用例之间的依赖。TestNG中通过dependsOnMethods属性来配置依赖方法。
实现如下:
@Test(dependsOnMethods = { "minus" }) public void add() { Assert.assertEquals(a.add(5, 6), 11); }
备注: add测试用例执行的前提条件是必须minus测试方法执行,如果minus用例的属性设置为enabled = false,那么执行测试的时候就会报错,因为minus不执行。 注意:被依赖的测试用例必须执行成功才运行下一个测试用例,dependsOnGroups依赖于测试组
TestNG自定义执行顺序
按照一定的顺序去执行测试方法, 通过priority属性去设 置,如下代码实现:
1 public class yihuqingjiu_demo { 2 @Test(priority=2) 3 public void print3(){ 4 System.out.println("壶"); 5 } 6 @Test(priority=0) 7 public void print1(){ 8 System.out.println("温"); 9 } 10 @Test(priority=1) 11 public void print2(){ 12 System.out.println("一"); 13 } 14 @Test(priority=4) 15 public void print5(){ 16 System.out.println("酒"); 17 } 18 @Test(priority=3) 19 public void print4(){ 20 System.out.println("清"); 21 } 22 }
执行顺序为print1--->print2--->print3--->print4--->print5
属性值为0代表最高优先级
还可以在testng.xml文件中设置,设置如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite1"> <test name="test" preserve-order="true"> <classes> <class name="com.ui.day4.test_demo"> <methods> <include name="print5" /> <include name="print2" /> <include name="print4" />
<include name="print1" />
<include name="print3" /> </methods> </class> </classes> </test> </suite>
preserve-order属性设置为true
依据include配置的顺序执行测试方法
TestNG参数化测试
软件测试中, 经常需要测试大量的数据集。 测试代码的逻辑完全一样, 只是测试的参数不一样。 这样我们就需要一种 “传递测试参数的机制” 。 避免写重复的测试代码。
TestNG提供了2种传递参数的方式:
第一种: testng.xml 方式使代码和测试数据分离,方便维护;
第二种: @DataProvider能够提供比较复杂的参数。(也叫data-driven testing)
使用testng.xml设置参数:
1、 参数在xml文件中可以在suite级别定义, 也可以在test级别定义;
2、 TestNG会尝试先在包含当前类的test标签中寻找参数, 如果没找到则在上层的suite标签中查找。 即在test标签中相同的参数对当前类当前方法的优先级比较高。
3、 TestNG支持这种传参方式的类型如下:
String、 int/Integer、 boolean/Boolean、 byte/Byte、 char/Character、double/Double、 float/Float、 long/Long、 short/Short
使用@DataProvider方式传参数:
只提供了一个字符串属性:名称,供测试方法作为传递参数的annotation使用两种DataProvider,一种是返回一个二维数组对象; 另外一种DataProvider是返回一个Iterator
DataProvider可以向测试方法传递任意类型任意数目的参数利用DataProvider提供不同的参数集合对一个测试方法进行多次调用
@DataProvider和testNG.xml两种方式的比较
1 public class NewTest { 2 WebDriver driver; 3 4 @BeforeSuite 5 public void reday(){ 6 driver=new ChromeDriver(); 7 driver.manage().window().maximize(); 8 driver.manage().timeouts().implicitlyWait(5,TimeUnit.SECONDS); 9 } 10 11 @Test(priority=0) 12 public void index() throws Exception{ 13 driver.get("http://127.0.0.1/iwebshop/"); 14 String title=driver.getTitle(); 15 //断言 16 //括号中前者是实际结果,后者是预期结果 17 Assert.assertEquals(title,"iWebShop开源电子商务平台"); 18 Thread.sleep(2000); 19 } 20 21 @Test(priority=1) 22 public void login() throws Exception{ 23 driver.findElement(By.cssSelector("p.loginfo a")).click(); 24 Thread.sleep(2000); 25 } 26 27 @DataProvider(name="test") 28 public static Object[][] obj(){ 29 return new Object[][]{{"username","654321"},{"username","123456"},{"username","654321"}}; 30 } 31 @Test(dataProvider="test",priority=2) 32 public void userpassword(String a,String b) throws Exception { 33 driver.findElement(By.className("gray")).sendKeys(a); 34 Thread.sleep(1000); 35 driver.findElement(By.cssSelector("input[name='password']")).sendKeys(b); 36 Thread.sleep(1000); 37 System.out.println(a+":"+b); 38 driver.findElement(By.className("submit_login")).click(); 39 Thread.sleep(2000); 40 41 }
用户名和密码依次传递给变量a和b,重复登录操作