一、TestNG介绍
TestNG是一个设计用来简化广泛的测试需求的测试框架,从单元测试(隔离测试一个类)到集成测试(测试由有多个类多个包甚至多个外部框架组成的整个系统,例如运用服务器)。
编写一个测试的过程有三个典型步骤:
* 编写测试的 业务逻辑并在代码中插入TestNG annotation
* 将测试信息添加到testng.xml文件或者build.xml中
* 运行TestNG
下面是这篇文档使用的概念:
* suite由xml文件描述。它包含一个或多个测试并被定义为<suite>标签
* test由<test>描述并包含一个或者多个TestNG类
* TestNG类是包含至少一个TestNG annotation的java类,由<class>标签描述并包含一个或多个测试方法
* 测试方法是源文件中带有@Testd注释的java方法
TestNG测试可以被@BeforeXXX 和 @AfterXXX annotations配置,容许在特定点的前后执行一些java逻辑,这些点上面已经列出。
这份手册的剩余部分将讲述以下内容:
* 所有的annotation列表并带有简短说明,为TestNG的多种功能性提供参考, 你可能需要参考为每个annotation提供的代码片段来学习细节。
* testng.xml文件描述,它的语法和如果指定它。
* 多个特性的详细列表和怎样结合annotation和testng.xml来使用它们
注:上面的内容很简短,但是请注意其中的一些细节。
1. TestNG是一个设计用来简化广泛的测试需求的测试框架,从单元测试到集成测试
这个是TestNG设计的出发点,不仅仅是单元测试,而且可以用于集成测试。设计目标的不同,对比junit的只适合用于单元测试,TestNG无疑走的更远。
可以用于集成测试,这个特性是我选择TestNG的最重要的原因。
2. 测试的过程的三个典型步骤,注意和junit(4.0)相比,多了一个将测试信息添加到testng.xml文件或者build.xml
测试信息尤其是测试数据不再写死在测试代码中,好处就是修改测试数据时不需要修改代码/编译了,从而有助于将测试人员引入单元测试/集成测试。
1.TestNG基本注解(Annotation)
注解 | 描述 |
---|---|
@BeforeSuite | 注解的方法将只运行一次,运行所有测试前此套件中。 |
@AfterSuite | 注解的方法将只运行一次此套件中的所有测试都运行之后。 |
@BeforeClass | 注解的方法将只运行一次先行先试在当前类中的方法调用。 |
@AfterClass | 注解的方法将只运行一次后已经运行在当前类中的所有测试方法。 |
@BeforeTest | 注解的方法将被运行之前的任何测试方法属于内部类的 标签的运行。 |
@AfterTest | 注解的方法将被运行后,所有的测试方法,属于内部类的标签的运行。 |
@BeforeGroups | 组的列表,这种配置方法将之前运行。此方法是保证在运行属于任何这些组第一个测试方法,该方法被调用。 |
@AfterGroups | 组的名单,这种配置方法后,将运行。此方法是保证运行后不久,最后的测试方法,该方法属于任何这些组被调用。 |
@BeforeMethod | 注解的方法将每个测试方法之前运行。 |
@AfterMethod | 被注释的方法将被运行后,每个测试方法。 |
@DataProvider |
标志着一个方法,提供数据的一个测试方法。注解的方法必须返回一个Object[][],其中每个对象[]的测试方法的参数列表中可以分配。
该@Test 方法,希望从这个DataProvider的接收数据,需要使用一个dataProvider名称等于这个注解的名字。 |
@Factory | 作为一个工厂,返回TestNG的测试类的对象将被用于标记的方法。该方法必须返回Object[]。 |
@Listeners | 定义一个测试类的监听器。 |
@Parameters | 介绍如何将参数传递给@Test方法。 |
@Test | 标记一个类或方法作为测试的一部分。 |
alwaysRun 对于每个bufore方法(beforeSuite, beforeTest, beforeTestClass 和 beforeTestMethod, 但是不包括 beforeGroups):
如果设置为true,被配置的方法将总是运行而不管它属于哪个组。
对于after方法(afterSuite, afterClass, ...): 如果设置为true,被配置的方法甚至在一个或多个先调用的方法失败或被忽略时也将运行。
dependsOnGroups 这个方法依赖的组列表
dependsOnMethods 这个方法依赖的方法列表
enabled 这个类的方法是否激活
groups 这个类或方法所属的分组列表
inheritGroups 如果设置为true,这个方法被属于在类级别被@Test annotation指定的组
@DataProvider 标记一个方法用于为测试方法提供数据。
被注释的方法必须返回Object[][], 其中每个Object[]可以指派为这个测试方法的参数列表。
从这个DataProvider接收数据@Test方法需要使用一个和当前注释相同名称的dataProvider名称
name 这个DataProvider的名称
@Factory 标记方法作为一个返回对象的工厂,这些对象将被TestNG用于作为测试类。这个方法必须返回Object[]
@Parameters 描述如何传递参数给@Test方法
value 用于填充这个方法的参数的变量列表
@Test 标记一个类或方法作为测试的一部分
alwaysRun 如果设置为true,这个测试方法将总是运行,甚至当它依赖的方法失败时。
dataProvider 这个测试方法的data provider的名称
dataProviderClass 用于查找data provider的类。
如果不指定,将在当前测试方法所在的类或者它的基类上查找data provider。
如果这个属性被指定, 则data provider方法需要是指定类的static方法。
dependsOnGroups 当前方法依赖的组列表
dependsOnMethods 当前方法依赖的方法列表
description 当前方法的描述
enabled 当前类的方法/方法是否被激活
expectedExceptions 测试方法期望抛出的异常列表。如果没有异常或者抛出的不是列表中的任何一个,当前方法都将标记为失败.
groups 当前类/方法所属的组列表
invocationCount 当前方法被调用的次数
successPercentage 当前方法期望的成功率
sequential 如果设置为true,当前测试类上的所有方法保证按照顺序运行。甚至测试们在parallel="true"的情况下.
这个属性只能用于类级别,如果用于方法级别将被忽略。
timeOut 当前方法容许花费的最大时间,单位毫秒。
threadPoolSize 当前方法的线程池大小。方法将被多线程调用,次数由invocationCount参数指定
注意:如果invocationCount没有指定则这个属性将被忽略
注:
上面是TestNG中用到的annotation列表,从中我们可以看到TestNG提供的一些特性
1. before方法和after方法 带来了足够丰富的测试生命周期控制
2. dependsOnGroups/dependsOnMethods 提供了依赖检查机制,并可以严格控制执行顺序
3. DataProvider 使得对同一个方法的测试覆盖变的非常轻松,非常适合进行边界测试,只要给出多种测试数据就可以针对一个测试方法进行覆盖
4. expectedExceptions 使得异常测试变的非常轻松
5. invocationCount/threadPoolSize 终于可以简单的直接进行多线程测试了,这个绝对是junit的超级弱项,回想junit中那个万恶的System.exist(0)...
6. timeOut 终于不用死等然后手工强行关闭测试,TestNG想的太周到了
2.Testng.xml文件按顺序执行Case:
在testng.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="TankLearn2.Learn.TestNGLearn1"> <methods> <include name="TestNgLearn3" /> <include name="TestNgLearn1" /> <include name="TestNgLearn2" /> </methods> </class> </classes> </test> </suite>
3.TestNG组测试:
TestNG中可以把测试用例分组,这样可以按组来执行测试用例比如:
package TankLearn2.Learn; import org.testng.annotations.Test; public class GroupTest { @Test(groups = {"systemtest"}) public void testLogin(){ System.out.println("this is test login"); } @Test(groups = {"functiontest"}) public void testOpenPage(){ System.out.println("this is test Open Page"); } }
然后在testng.xml中 按组执行测试用例:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite1"> <test name="test1"> <groups> <run> <include name="functiontest" /> </run> </groups> </test> </suite>4.TestNg参数化测试:
软件测试中,经常需要测试大量的数据集。 测试代码的逻辑完全一样,只是测试的参数不一样。 这样我们就需要一种 “传递测试参数的机制”。 避免写重复的测试代码
TestNG提供了2种传递参数的方式。
第一种: testng.xml 方式使代码和测试数据分离,方便维护
第二种:@DataProvider能够提供比较复杂的参数。 (也叫data-driven testing)
方法一: 通过testng.xml 传递参数给测试代码package TankLearn2.Learn; import org.testng.annotations.Parameters; import org.testng.annotations.Test; public class ParameterizedTest1 { @Test @Parameters("test1") public void ParaTest(String test1){ System.out.println("This is " + test1); } }testng.xml:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite1"> <parameter name="test1" value="Tank" /> <parameter name="test1" value="Xiao" /> <test name="test12"> <classes> <class name="TankLearn2.Learn.ParameterizedTest1" /> </classes> </test> </suite>方式二: 通过DataProvider传递参数
package TankLearn2.Learn; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class DataProviderLearn { @DataProvider(name="user") public Object[][] Users(){ return new Object[][]{ {"root","passowrd"}, {"cnblogs.com", "tankxiao"}, {"tank","xiao"} }; } @Test(dataProvider="user") public void verifyUser(String userName, String password){ System.out.println("Username: "+ userName + " Password: "+ password); } }
5.TestNG测试方法通过测试分组依赖实现
①分组依赖
- package com.easyway.testng;
- import org.testng.annotations.Test;
- /**
- * 、测试方法直接通过测试分组依赖的实现
- *
- * 2013-11-19 下午2:54:17
- *
- */
- public class TestGroupDependenciesDataTest {
- @Test(groups = { "init" })
- public void serverStartedOk() {
- System.out.println("===================serverStartedOk==============");
- }
- @Test(groups = { "init" })
- public void initEnvironment() {
- System.out.println("===================initEnvironment==============");
- }
- @Test(dependsOnGroups = { "init.*" })
- public void method1() {
- System.out.println("===================method1==============");
- }
- }
②Dependencies in XML
<
test
name
=
"My suite"
>
< groups > |
< dependencies > |
< group name = "c" depends-on = "a b" /> |
< group name = "z" depends-on = "c" /> |
</ dependencies > |
</ groups > |
</ test > |
The <depends-on> attribute contains a space-separated list of groups.
6.测试类有很多方法需要测试或测试类需要测试很多次工厂允许创建动态测试,例如:希望创建一个测试方法,将多次用不同的值访问Web站点页面多次(这样会变得很混乱)。
TestWebServer.java
public
class
TestWebServer {
@Test (parameters = { "number-of-times" }) |
public void accessPage( int numberOfTimes) { |
while (numberOfTimes-- > 0 ) { |
// access the web page |
} |
} |
}
testng.xml
<test name=
"T1"
>
<parameter name= "number-of-times" value= "10" /> |
< class name= "TestWebServer" /> |
</test> |
<test name= "T2" > |
<parameter name= "number-of-times" value= "20" /> |
< class name= "TestWebServer" /> |
</test> |
<test name= "T3" > |
<parameter name= "number-of-times" value= "30" /> |
< class name= "TestWebServer" /> |
</test>
WebTestFactory.java
public
class
WebTestFactory {
@Factory |
public Object[] |
Object[] result = new Object[ 10 ]; |
for ( int i = 0 ; i < 10 ; i++) { |
result[i] = new WebTest(i * 10 ); |
} |
return result; |
} |
}
the new test class is now:
WebTest.java
public
class
WebTest {
private int m_numberOfTimes; |
public WebTest( int numberOfTimes) { |
m_numberOfTimes = numberOfTimes; |
} |
@Test |
public void testServer() { |
for ( int i = 0 ; i < m_numberOfTimes; i++){ |
// access the web page |
} |
} |
}
工厂也可以用于数据提供者,您可以利用这个功能用@ factory注释在常规方法或构造函数。这是一个工厂一个构造函数的例子:
@Factory
(dataProvider =
"dp"
)
public FactoryDataProviderSampleTest( int n) { |
super (n); |
} |
@DataProvider |
static public Object[][] dp() { |
return new Object[][] { |
new Object[] { 41 }, |
new Object[] { 42 }, |
}; |
}
7.JUnit Test:TestNG可以运行Junit3和Junit4,你只需要做的就是把JUnit.jar文件放在classpath上,
testng.xml
< test name = "Test1" junit = "true" > |
< classes > |
<!-- ...
-->
8.TestNG注释的使用:
TestNG允许在运行使用注释,尤其是当代码在源码中是有用的,但是在特殊情况是你希望不用他们
- package com.easyway.testng.junit;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Method;
- import org.testng.IAnnotationTransformer;
- import org.testng.annotations.ITestAnnotation;
- public class MyTransformer implements IAnnotationTransformer {
- /*
- * (non-Javadoc)
- *
- * @see org.testng.IAnnotationTransformer#transform(org.testng.annotations.
- * ITestAnnotation, java.lang.Class, java.lang.reflect.Constructor,
- * java.lang.reflect.Method)
- */
- @SuppressWarnings("rawtypes")
- @Override
- public void transform(ITestAnnotation annotation, Class testClass,
- Constructor testConstructor, Method testMethod) {
- System.out.println(" MyTransformer "+testMethod);
- if ("test1".equals(testMethod.getName())) {
- annotation.setInvocationCount(5);
- }
- }
- }
- package com.easyway.testng.junit;
- import org.testng.TestNG;
- public class MyTransformerTestMain {
- public static void main(String[] args) {
- TestNG tng = new TestNG();
- tng.setAnnotationTransformer(new MyTransformer());
- tng.setTestClasses(new Class[]{MyTransferTest.class});
- tng.run();
- }
- }