实验简介
TestNG是Java中的一个测试框架, 类似于JUnit 和NUnit,功能都差不多,TestNG也是以JUnit和NUnit的一些特性作为参考开发而成的,只是功能稍微强大一些,使用也更方便。
测试人员一般用TestNG来写自动化测试。开发人员一般用JUnit写单元测试。
但是这并不是必然的,无论选用哪种框架,并不决定我们的代码级测试开发工作是否做得很好。
实验目的
1.掌握TestNG的使用以及与JUnit的区别。
2.为后续学习其它基于上述两种框架的测试技术打下基础。
实验流程
1. 安装配置TestNG。
(1) 通过Eclipse的菜单Help -> Install New Software:
输入网址:http://beust.com/eclipse安装即可,视网络情况可能会花较长时间。
(2) 直接下载文件并进行离线安装:
直接去网址http://dl.bintray.com/testng-team/testng-eclipse-release/zipped/下载离线安装包。将下载的文件解压,将目录features和plugins下面的文件复制到Eclipse目录下相对应的文件夹下,重启Eclipse即可。
2. 验证TestNG安装。
在File -> New -> Other中,我们能够看到可以创建TestNG class的文件,则说明安装成功。
3. 导入TestNG库文件到当前项目。
进入菜单Project -> Properties -> Java Build Path -> Libraries,选择 Add Library,浏览到TestNG类库,点击确认即可将TestNG需要用到的jar包导入到当前项目中,这一操作跟JUnit类似。
4. 完成对isNumber和splitString的简单测试。
先实现测试代码和断言,同样使用@Test为每个测试用例进行注解:
package com.woniuxy.testng; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import org.testng.Assert; import com.woniuxy.compare.StringHandle; public class StringHandleTest { @BeforeTest public void init() { System.out.println("测试用例正在执行..."); } @Test public void isNumber() { StringHandle stringHandle = new StringHandle(); String source = "123.45"; boolean actual = stringHandle.isNumber(source); Assert.assertTrue(actual); } @Test public void splitString() { StringHandle stringHandle = new StringHandle(); String source = "333,111,222,666"; Integer[] expect = {333, 111, 222, 666}; Integer[] actual = stringHandle.splitString(source, ","); Assert.assertEquals(expect, actual); } @AfterTest public void end() { System.out.println("测试用例执行完成..."); } }
5. 使用Eclipse方式运行。
在包com.woniuxy.testng下,右键选择上述测试类:“StringHandleTest”,选择“Run As” -> TestNG Test”的方式运行。运行结果如下:
同样,我们在另外一个视图:Results of running class …中,也可以看到详细信息,还可以用浏览器打开HTML格式的报表:
6. 使用XML方式运行。
除了使用Run As的方式执行测试以外,TestNG提供了另外一种更加灵活的执行手段:通过XML文件执行。我们可以在当然包下面创建一个XML文件,命名为:ArrayCompareTestSuite.xml,格式如下:
在此XML文件上,点击右键,Run As -> TestNG Suite,即可开始运行。注意一下,上述XML中,我们其实运行了两个测试类,一个叫ArrayHandleTest,一个叫StringHandleTest,我们可以通过设定两个测试类的顺序来决定先运行哪个测试。这也是TestNG非常方便的地方。
7. 为ArrayHandle类快速添加测试类。
除了直接创建一个普通的Java类文件来创建TestNG的测试用例以外,我们还可以有一种相对快速的创建测试类的办法。
(1) 选中要进行测试的被测类,比如此处我们选择com.woniuxy.compare包下的ArrayHandle.java,右键,选择New -> Other -> TestNG –> TestNG Class,下一步,选择要添加测试用例的方法:
(2) 输入相应的包信息,注意路径和测试代码的目标包,写错了会重复创建包,没有必要:
(3) 自动生成部分测试代码:
package com.woniuxy.testng; import org.testng.annotations.Test; public class ArrayHandleTest { @Test public void arrayCompare() { throw new RuntimeException("Test not implemented"); } @Test public void arraySort() { throw new RuntimeException("Test not implemented"); } }
当然,这样的代码只是一个框架而已,没有实际用途。
(4) 完善测试驱动程序:
package com.woniuxy.testng; import org.testng.Assert; import org.testng.annotations.Test; import com.woniuxy.compare.ArrayHandle; public class ArrayHandleTest { ArrayHandle ah = new ArrayHandle(); @Test public void arrayCompare() { Integer[] source = {22, 33, 55, 77, 11, 99, 66}; Integer[] expect = {11, 22, 33, 55, 66, 77, 99}; Assert.assertFalse(ah.arrayCompare(source, expect)); } @Test public void arraySort() { Integer[] source = {22, 33, 55, 77, 11, 99, 66}; Integer[] expect = {11, 22, 33, 55, 66, 77, 99}; Integer[] actual = ah.arraySort(source); Assert.assertEquals(expect, actual); } }
8. TestNG按顺序执行Case。
针对一个测试类中,有多个测试用例的情况,我们也可以为每一个测试方法单独指定运行顺序。就像执行多个测试类一样,我们通过配置XML文件的顺序来进行:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite-2"> <test name="Test-2" preserve-order="true"> <classes> <class name="com.woniuxy.testng.ArrayHandleTest"> <methods> <include name="arraySort" /> <include name="arrayCompare" /> </methods> </class> </classes> </test> </suite>
9. TestNG组测试。
在TestNG中,我们还可以把测试用例进行分组,比如本次测试我们只测试ArrayHandle的arraySort和StringHandle的isNumber两个方法,那么这个时候,我们通过把这两条测试用例指定为同一组,即可实现交叉执行。
(1) 先在ArrayHandleTest类中的arraySort的@Test注解后面加上 @Test(groups = {"group1"}):
@Test(groups = {"group1"}) public void arraySort() { Integer[] source = {22, 33, 55, 77, 11, 99, 66}; Integer[] expect = {11, 22, 33, 55, 66, 77, 99}; Integer[] actual = ah.arraySort(source); Assert.assertEquals(expect, actual); }
(2) 再在StringHandleTest类中的isNumber的注解上加上:@Test(groups = {"group1","group2"}),其实大家可以看到,groups后面跟的就是一个字符串数组,基于此来判断哪些用例应该被执行。一个测试用例是可以属于多个组的。
(3) 编写XML执行文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite-1"> <test name="Test-1"> <groups> <run> <include name="group1" /> </run> </groups> <classes> <class name="com.woniuxy.testng.ArrayHandleTest" /> <class name="com.woniuxy.testng.StringHandleTest" /> </classes> <!-- 也可以通过指定包名来快速完成,但是不要与类名同时指定 <packages> <package name="com.woniuxy.testng"></package> </packages> --> </test> </suite>
这样,执行该XML文件,即只会执行groups = {“group1”}的测试用例。需要注意的是,如果分组位于多个类中,我们需要在XML中一起指定完整。
10. 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 | 标记一个类或方法作为测试的一部分。 |
11. TestNG异常测试。
package com.woniuxy.testng; import org.testng.annotations.Test; public class ExceptionTest { @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp="NullPoint") public void testException(){ throw new IllegalArgumentException("NullPoint"); } }
12. TestNG参数化测试。
参数化测试的目的主要为了测试脚本与测试数据分离,这也是自动化测试框架的标配功能。在TestNG中,我们可以通过两种方式实现参数化测试。
(1) 使用XML文件方式
先定义测试用例,注意参数的注解格式和对应的测试用例的参数传递方式和参数类型:
@Test @Parameters({"number","expect"}) public void isNumberParam(String number, boolean expect) { StringHandle stringHandle = new StringHandle(); String source = number; boolean actual = stringHandle.isNumber(source); Assert.assertEquals(actual, expect); }
再编写执行XML:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite-1"> <test name="Test-3"> <parameter name="number" value="12345" /> <parameter name="expect" value="true" /> <classes> <class name="com.woniuxy.testng.StringHandleTest" /> </classes> </test> </suite>
如果我们想通过参数化测试多条用例,应该怎么办呢?如果我们要传递的不是基础类型,而是一个数组,又应该怎么办呢?
(2) 使用@DataProvider注解
package com.woniuxy.testng; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import com.woniuxy.compare.StringHandle; public class StringHandleDP { @DataProvider(name="isNumber") public Object[][] Users(){ return new Object[][]{ {"12345",true}, {"123.45", true}, {"-12345", true}, {"123T5", false}, {"0.123", true} }; } @Test(dataProvider="isNumber") public void isNumber(String number, boolean expect) { StringHandle stringHandle = new StringHandle(); String source = number; boolean actual = stringHandle.isNumber(source); Assert.assertEquals(actual, expect); } }
调用数据方法:
@Test(dataprovide="XXX")
说明:
(1) XXX为@DataProvide声明的一个名字,返回的是一个Object数组,即可以存放任意类型数据。
(2) 方法的执行次数为赋值参数的遍数。比如提供数组为1行,则只执行一次;如果是数组为3行,则执行3次。
其他扩展:
(1) @DataProvide可写在单独的Class里,增强复用性。
这时调用该数据的方法为:@Test(dataprovide="XXX",dataClass=YYY.class)
说明:读取YYY.class下的@DataProvide为XXX的Object数组数据
(2) @DataProvide下定义的数组,可以通过其他文件读取,比如读取Excel,返回一个Object数组。这样可以实现更加灵活的外部数据读取。
13. TestNG多线程测试
测试程序:
@Test(threadPoolSize = 3, invocationCount = 6, timeOut = 1000) public void isNumber() { StringHandle stringHandle = new StringHandle(); String source = "-1235"; boolean actual = stringHandle.isNumber(source); Assert.assertTrue(actual); }
或使用执行XML:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Suite3" parallel="methods" thread-count="5"> <test name="Test3"> <classes> <class name="com.woniuxy.testng.StringHandleThread" /> </classes> </test> </suite>
指定parallel的值可为:methods, classes, tests, instances,目前笔者环境无法调试通过。
14. TestNG忽略测试。
如果某次执行,我们不需要测试用例参与,则可以在@Test后面添加:
@Test(enabled=false)
15. TestNG 依赖测试。
有时候,我们需要按顺序来调用测试用例, 那么测试用例之间就存在依赖关系。 TestNG支持测试用例之间的依赖,如下代码所示:
@Test(dependsOnMethods = {"splitString"}) public void isNumber() { ……… }
一旦测试用例之间产生了依赖关系,那么就会优先执行被依赖的测试用例,比如上例中就会优先把splitString这个测试用例执行了,才执行isNumber.
16. TestNG测试结果报告。
我们可以在Eclipse中利用浏览器打开TestNG的HTML格式的报告,我们也可以在执行XML中设置报告的显示级别:共有0-10的级别,其中0表示无,10表示最详细。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite-4"> <test name="Test-4" verbose="2"> <classes> <class name="com.woniuxy.testng.StringHandleTest" /> </classes> </test> </suite>
思考练习
1. JUnit与TestNG有哪些异同,你更喜欢哪个?
2.如果不使用任何测试框架,是否会影响我们的自动化测试工作的进行?
3. 参数化测试中,基于XML的@Parameters和基于源代码的@DataProvider两种方式哪一种更好?如果要想多参数值多循环运行,XML方式是否可行?
4. 代码级接口测试框架究竟价值有多大?特别是对测试人员来说?