TestNG介绍
TestNG是Java中的一个测试框架, 类似于JUnit 和NUnit, 功能都差不多, 只是功能更加强大,使用也更方便
Eclipse安装TestNG插件
1)在线安装
在eclipse中,Help-> Install NewSoftware,Add "http://beust.com/eclipse"
1. 将解压后的文件..\eclipse-testng离线包\features\org.testng.eclipse_6.9.9.201510270734 文件夹 放到 eclipse--》features目录下
2. 将解压后的文件..\eclipse-testng离线包\plugins\org.testng.eclipse_6.9.8.201510130443 文件夹 放到 eclipse--》plugins目录下
3. 重启eclipse
4. 验证是否安装成功,file-->new-->other-->TestNg
编写简单的测试
<strong><span lang="EN-US" style="font-size: 10.5pt; font-family: 宋体;">publicclass EmployeeDetails {</span></strong>
private String name;
private double monthlySalary;
private int age;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the monthlySalary
*/
public double getMonthlySalary() {
return monthlySalary;
}
/**
* @param monthlySalary the monthlySalary to set
*/
public void setMonthlySalary(double monthlySalary) {
this.monthlySalary = monthlySalary;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
}
创建 EmpBusinessLogic类,用于计算员工年薪
<span style="font-weight: normal;"><span style="font-size:14px;">public class EmpBusinessLogic {
// Calculate the yearly salary of employee
public double calculateYearlySalary(EmployeeDetails employeeDetails){
double yearlySalary=0;
yearlySalary = employeeDetails.getMonthlySalary() * 12;
return yearlySalary;
}
// Calculate the appraisal amount of employee
public double calculateAppraisal(EmployeeDetails employeeDetails){
double appraisal=0;
if(employeeDetails.getMonthlySalary() < 10000){
appraisal = 500;
}else{
appraisal = 1000;
}
return appraisal;
}
}</span></span>
在project中添加TestNG库,project -> build path -> configure build path ->library -? add library -> TestNG
添加成功
也可以之间创建一个Java类,自己import需要的包
<span style="font-weight: normal;"><span style="font-size:14px;">import org.testng.Assert;
import org.testng.annotations.Test;
public class TestEmployeeDetails {
EmpBusinessLogic empBusinessLogic = new EmpBusinessLogic();
EmployeeDetails employee = new EmployeeDetails();
@Test
public void testCalculateAppriasal() {
employee.setName("Rajeev");
employee.setAge(25);
employee.setMonthlySalary(8000);
double appraisal = empBusinessLogic
.calculateAppraisal(employee);
Assert.assertEquals(500, appraisal, 0.0, "500");
}
// test to check yearly salary
@Test
public void testCalculateYearlySalary() {
employee.setName("Rajeev");
employee.setAge(25);
employee.setMonthlySalary(8000);
double salary = empBusinessLogic
.calculateYearlySalary(employee);
Assert.assertEquals(96000, salary, 0.0, "8000");
}
}</span></span>
textng.xml文件
<span style="font-weight: normal;"><span style="font-size:14px;"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
<test name="test1">
<classes>
<class name="TestEmployeeDetails"/>
</classes>
</test>
</suite></span></span>
运行testng.xml->右击Run As->TestNg.suite,可以在控制台中看到运行结果
此外,TestNG创建了一个HTML报告,会自动在当前目录下创建一个文件夹名为test-output,打开并加载index.html,可以看到测试结果页面
xml文件
- 一个suite(套件)由一个或多个测试组成
- 一个test(测试)由一个或多个类组成
- 一个class(类)由一个或多个方法组成
基本注解
注解 | 描述 |
---|---|
@BeforeSuite | 注解的方法将只运行一次,运行所有测试前此套件中。 |
@AfterSuite | 注解的方法将只运行一次此套件中的所有测试都运行之后。 |
@BeforeClass | 注解的方法将只运行一次先行先试在当前类中的方法调用。 |
@AfterClass | 注解的方法将只运行一次后已经运行在当前类中的所有测试方法。 |
@BeforeTest | 注解的方法将被运行之前的任何测试方法属于内部类的 <test>标签的运行。 |
@AfterTest | 注解的方法将被运行后,所有的测试方法,属于内部类的<test>标签的运行。 |
@BeforeGroups | 组的列表,这种配置方法将之前运行。此方法是保证在运行属于任何这些组第一个测试方法,该方法被调用。 |
@AfterGroups | 组的名单,这种配置方法后,将运行。此方法是保证运行后不久,最后的测试方法,该方法属于任何这些组被调用。 |
@BeforeMethod | 注解的方法将每个测试方法之前运行。 |
@AfterMethod | 被注释的方法将被运行后,每个测试方法。 |
@DataProvider |
标志着一个方法,提供数据的一个测试方法。注解的方法必须返回一个Object[] [],其中每个对象[]的测试方法的参数列表中可以分配。
该@Test 方法,希望从这个DataProvider的接收数据,需要使用一个dataProvider名称等于这个注解的名字。 |
@Factory | 作为一个工厂,返回TestNG的测试类的对象将被用于标记的方法。该方法必须返回Object[]。 |
@Listeners | 定义一个测试类的监听器。 |
@Parameters | 介绍如何将参数传递给@Test方法。 |
@Test | 标记一个类或方法作为测试的一部分。 |
套件测试
suite的属性
属性 | 描述 |
---|---|
name | 此套件的名称。这是一个强制性的属性。 |
verbose | 这个运行级别或冗长。 |
parallel | 由TestNG 运行不同的线程来运行此套件。 |
thread-count | 使用的线程数,如果启用并行模式(忽略其他方式)。 |
annotations | 在测试中使用注释的类型。 |
time-out | 默认的超时时间,将用于本次测试中发现的所有测试方法。 |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite1"> <test name="exampletest1"> <classes> <class name="Test1" /> </classes> </test> <test name="exampletest2"> <classes> <class name="Test2" /> </classes> </test> </suite>
组测试
<div><span style="font-family:Consolas, Courier New, Courier, mono, serif;color:#5c5c5c;"><span style="line-height: 18px;"></span></span><pre name="code" class="java">public class TestngGroups {
@Test(groups = { "functest", "checkintest" })
public void testMethod1() {
System.err.println("groups = { functest, checkintest }");
}
@Test(groups = { "functest", "checkintest" })
public void testMethod2() {
System.err.println("groups = { functest, checkintest }");
}
@Test(groups = { "functest" })
public void testMethod3() {
System.err.println("groups = { functest }");
}
@Test(groups = { "checkintest" })
public void testMethod4() {
System.err.println("groups = { checkintest }");
}
}
TestNG.xml使用时,<group>,<run>标签用来指定或排除一部分组
<pre name="code" class="html"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="framework_testng">
<test name="TestGroups">
<groups>
<run>
<include name="functest" />
<exclude name="checkintest" />
</run>
</groups>
<classes>
<class name="com.dragon.testng.annotation.TestngGroups" />
</classes>
</test>
</suite>
分组测试执行原则,只保留最小集合进行执行。例如以功能点为粒度进行划分,然后以总的testng.xml将各个功能点的配置汇总起来
注意执行测试的默认顺序是按照testng.xml文件里给定的顺序执行的。如果不希望按此顺序执行,使用preserve-order=false属性,例如:<test name="Regression1" preserve-order="false">
参数化
TestNG改进了传统测试框架无法传递参数的缺点,它提供了两种传递参数的简单方法:
(1)在测试方法上加@Parameters标签,然后在testng.xml给出参数;
(2)指定@Dataproviders
第一种方式的缺点很明显,它只支持java基本类型,并且在构造值时,无法包含计算逻辑得到需要的参数。
第二种方式可以向测试方法传递任何有效的java类型。我们倾向于第二种方法来构造参数。
在使用TestNG进行测试时,经常会使用到一些参数化配置,比如数据库、连接池、线程池数。
@Parameters标签方法
// @Parameters注解内对应的参数名称和配置文件中的key必须是相同
@Parameters({ "<span style="font-family: Arial, Helvetica, sans-serif;">secondName</span>" })
@Test
public void testSingleString(String secondName) {
System.err.println("Invoked testString " + secondName);
assert "Cedric".equals(secondName);
}
@Parameters({ "count" })
@Test
public void testSingleInteger(Integer count) {
System.err.println("Invoked count " + count);
assert count.intValue() == 8;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<!-- data-provider-thread-count="20" 共享线程池配置 -->
<suite name="framework_testng" data-provider-thread-count="20">
<parameter name="secondname" value="Cedric" />
<parameter name="count" value="8" />
<parameter name="datasource" value="com.dbcp.source" />
<parameter name="jdbcDriver" value="com.mysql.jdbc.driver" />
<parameter name="poolSize" value="10" />
<test verbose="2" name="TestGroups">
<classes>
<class name="com.dragon.testng.annotation.TestngParameters" />
</classes>
</test>
</suite>
@Dataproviders标签方法
@DataProvider(name = "DP1")
public Object[][] createData() {
Object[][] retObjArr = { { "001", "Jack", "London" },
{ "002", "John", "New York" }, { "003", "Mary", "Miami" },
{ "004", "George", "california" } };
return (retObjArr);
}
@Test(dataProvider = "DP1")
public void testEmployeeData(String empid, String empName, String city) {
System.err.println(empid);
System.err.println(empName);
System.err.println(city);
}
@DataProvider(name = "iterator")
public Iterator<Object[]> getData() {
Set<Object[]> set = new HashSet<Object[]>();
set.add(new String[] { "hello" });
Iterator<Object[]> iterator = set.iterator();
return iterator;
}
@Test(dataProvider = "iterator")
public void testIteraorData(String iterator) {
System.err.println("iterator .. " + iterator);
}
DP1数组内的每一组数据都会作为一个测试用例执行
注意要点:
1.我们的@DataProvider方法可以通过读取Excel、数据库、properties文件等方式进行获取,这个取决于实际测试用例的设计和项目的需要,
2.其返回值是返回一个二维数组,数组内的二维元素个数必须和调用方法的参数一致,
3.这个一致包括了个数和顺序以及类型,否则如果类型不匹配或无法自动转换时就会抛出类型转换异常,而参数个数不匹配也会抛出参数缺失异常。
测试的依赖与分组
测试方法之间的依赖是一种很常见的需求,您也许认为,测试之间的依赖不是破坏了测试方法之间的隔离性吗?确实是这样的,但是有时为了这种隔离性,在彼此隔离的测试方法当中要付出很大的代价去相互模拟,所以为了方便起见,testng提供了这种依赖的方式。
Testng当中通过@Test的属性dependsOnMethods,dependsOnGroups来实现针对方法和分组的依赖。
依赖还包括软依赖和硬依赖。硬依赖是很强的关联,如果被依赖的测试失败,那么依赖它的测试会跳过。而软依赖则不会跳过。通过给@Test设定alwaysRun=true来实现软依赖。使用依赖时需要注意的是要避免循环依赖
import org.testng.Assert;
import org.testng.annotations.Test;
public class DependencyTestUsingAnnotation {
String message = "Manisha";
MessageUtil messageUtil = new MessageUtil(message);
@Test
public void testPrintMessage() {
System.out.println("Inside testPrintMessage()");
message = "Manisha";
Assert.assertEquals(message, messageUtil.printMessage());
}
@Test(dependsOnMethods = { "initEnvironmentTest" })
public void testSalutationMessage() {
System.out.println("Inside testSalutationMessage()");
message = "Hi!" + "Manisha";
Assert.assertEquals(message, messageUtil.salutationMessage());
}
@Test
public void initEnvironmentTest() {
System.out.println("This is initEnvironmentTest");
}
}
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
<test name="test1">
<classes>
<class name="DependencyTestUsingAnnotation" />
</classes>
</test>
</suite>
验证输出
This is initEnvironmentTest Inside testPrintMessage() Manisha Inside testSalutationMessage() Hi!Manisha
异常测试
TestNG跟踪异常处理代码提供了一个选项。可以测试是否需要代码抛出异常或不抛出。 @Test注释expectedExceptions 参数一起使用。
import org.testng.Assert;
import org.testng.annotations.Test;
public class ExpectedExceptionTest {
String message = "Manisha";
MessageUtil messageUtil = new MessageUtil(message);
@Test(expectedExceptions = ArithmeticException.class)
public void testPrintMessage() {
System.out.println("Inside testPrintMessage()");
messageUtil.printMessage();
}
@Test
public void testSalutationMessage() {
System.out.println("Inside testSalutationMessage()");
message = "Hi!" + "Manisha";
Assert.assertEquals(message,messageUtil.salutationMessage());
}
}
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite1"> <test name="test1"> <classes> <class name="ExpectedExceptionTest" /> </classes> </test> </suite>
验证输出。testPrintMessage()测试的情况下会获得通过。
Inside testPrintMessage() Manisha Inside testSalutationMessage() Hi!Manisha