Test methods
测试方法用@Test注释。 除非在testng.xml中将allow-return-values设置为true,否则@Test注释的返回值的方法将被忽略:
<suite allow-return-values="true">
or
<test allow-return-values="true">
Test groups
TestNG允许您执行复杂的方法分组测试。 您不仅可以声明方法属于组,而且还可以指定包含其他组的组。 然后可以调用TestNG并要求包括一组特定的组(或正则表达式),同时排除另一组。 这为您提供了如何分区测试的最大灵活性,并且如果要反复运行两组不同的测试,则不需要重新编译任何内容。
groups 在您的testng.xml文件中指定,可以在<test>
或<suite>
标记下找到。 <suite>
标签中指定的组适用于下面所有的<test>
标签。 注意,这些标签中的组是累加的:如果在<suite>
中指定组“a”,在<test>
中指定“b”,那么在<test>
将包括“a”和“b”两个组。
例如,至少有两类测试是常见的:
- Check-in tests. 这些测试应该在提交新代码之前运行。他们通常能很快地执行,只是用来确保没有基本的功能单元出错崩溃。
- Functional tests. 这些测试应该涵盖软件的所有功能,并且每天至少运行一次,尽管理想情况下您希望连续运行它们。
通常,check-in tests 是 functional tests 的一个子集。TestNG允许您以非常直观的方式指定测试组。 例如,您可以通过说整个测试类属于“functest”组,并且另外几个方法属于组“checkintest”来构造测试:
public class Test1 {
@Test(groups = { "functest", "checkintest" })
public void testMethod1() {
}
@Test(groups = {"functest", "checkintest"} )
public void testMethod2() {
}
@Test(groups = { "functest" })
public void testMethod3() {
}
}
调用TestNG:
<test name="Test1">
<groups>
<run>
<include name="functest"/>
</run>
</groups>
<classes>
<class name="example1.Test1"/>
</classes>
</test>
其中,<groups>
下<include>
的name=functest
,那么僵运行此类中所有的测试方法;而当name=checkintest
时,只运行方法testMethod1() and testMethod2()。
这里是另一个例子,这次使用正则表达式。 假设你的一些测试方法不应该在Linux上运行,你的测试将如下所示:
@Test
public class Test1 {
@Test(groups = { "windows.checkintest" })
public void testWindowsOnly() {
}
@Test(groups = {"linux.checkintest"} )
public void testLinuxOnly() {
}
@Test(groups = { "windows.functest" )
public void testWindowsToo() {
}
}
您可以使用以下testng.xml仅启动Windows方法:
<test name="Test1">
<groups>
<run>
<include name="windows.*"/>
</run>
</groups>
<classes>
<class name="example1.Test1"/>
</classes>
</test>
Method groups
你还可以排除或包含单个方法:
<test name="Test1">
<classes>
<class name="example1.Test1">
<methods>
<include name=".*enabledTestMethod.*"/>
<exclude name=".*brokenTestMethod.*"/>
</methods>
</class>
</classes>
</test>
这可以有效的去停用一个单一的方法,而不必重新编译任何东西,但非常不建议使用这种技术,因为如果你开始重构Java代码,它可能使你的测试框架会被打破(标记中使用的正则表达式可能不再与您的方法匹配)。
Groups of groups
组也可以包括其他组。 这些组称为“MetaGroups”。 例如,您可能想要定义一个包含“checkintest”和“functest”的组“all”。 “functest”本身将包含组“windows”和“linux”,而“checkintest将只包含”windows“。下面是如何在属性文件中定义这个:
<test name="Regression1">
<groups>
<define name="functest">
<include name="windows"/>
<include name="linux"/>
</define>
<define name="all">
<include name="functest"/>
<include name="checkintest"/>
</define>
<run>
<include name="all"/>
</run>
</groups>
<classes>
<class name="test.sample.Test1"/>
</classes>
</test>
Exclusion groups
TestNG允许你包含或排除 groups。
例如,由于最近的更改,暂时中断的测试是很常见的,你没有时间修复破损。 但是,您确实希望清理运行功能测试,因此您需要停用这些测试,但请记住,需要重新激活这些测试。
一个解决这个问题的简单方法是创建一个名为“broken”的组,并使这些测试方法属于它。 例如,在上面的例子中,我知道testMethod2()现在出错了,所以我想禁用它:
@Test(groups = {"checkintest", "broken"} )
public void testMethod2() {
}
我现在需要做的是从运行中排除此组:
<test name="Simple example">
<groups>
<run>
<include name="checkintest"/>
<exclude name="broken"/>
</run>
</groups>
<classes>
<class name="example1.Test1"/>
</classes>
</test>
这样,我将得到一个干净的测试运行,同时跟踪哪些测试是出错的,需要稍后修复。
注意:您还可以通过使用@Test和@ Before / After注释之间的“enabled”属性来单独禁用测试。
Partial groups
您可以在类级别定义组,然后在方法级别添加组:
@Test(groups = { "checkin-test" })
public class All {
@Test(groups = { "func-test" )
public void method1() { ... }
public void method2() { ... }
}
在这个类中,method2()是在类级别定义的组“checkin-test”的一部分,而method1()属于“checkin-test”和“func-test”。
Parameters
测试方法肯能是有参数的。 您可以在每个测试方法上使用任意数量的参数,并指示TestNG使用@Parameters注解传递正确的参数。
有两种方法来设置这些参数:使用testng.xml或以编程方式。
Parameters from testng.xml
如果对参数使用简单的值,可以在testng.xml中指定它们:
@Parameters({ "first-name" })
@Test
public void testSingleString(String firstName) {
System.out.println("Invoked testString " + firstName);
assert "Cedric".equals(firstName);
}
在此代码中,我们指定您的Java方法的参数firstName应接收名为first-name的XML参数的值。 此XML参数在testng.xml中定义:
<suite name="My suite">
<parameter name="first-name" value="Cedric"/>
<test name="Simple example">
<-- ... -->
相同的技术可以用于@ Before / After和@Factory注解:
@Parameters({ "datasource", "jdbcDriver" })
@BeforeMethod
public void beforeTest(String ds, String driver) {
m_dataSource = ...; // look up the value of datasource
m_jdbcDriver = driver;
}
这一次,两个Java参数ds和driver将分别接收来自属性datasource和jdbc-driver的值。
参数可以声明为可选注释:
@Parameters("db")
@Test
public void testNonExistentParameter(@Optional("mysql") String db) { ... }
如果在testng.xml文件中找不到名为“db”的参数,那么您的测试方法将接收@Optional注释“mysql”中指定的默认值。
@Parameters注释可以放置在以下位置:
- 在任何已经有@Test,@ Before / After或@Factory注释的方法。
- 最多只有一个构造函数的测试类。 在这种情况下,当需要实例化测试类时,TestNG将调用此特定构造函数,并将参数初始化为testng.xml中指定的值。 此功能可用于将类中的字段初始化为随后将由测试方法使用的值。
注意
- XML参数以与在注释中找到的顺序相同的顺序映射到Java参数,如果数字不匹配,TestNG将发出错误。
- 参数范围。 在testng.xml中,可以在标签下或下声明它们。 如果两个参数具有相同的名称,则它是在中定义的具有优先级的参数。 如果需要指定适用于所有测试的参数,并且仅对某些测试覆盖其值,则这样的设计很方便。
Parameters with DataProviders
如果需要传递复杂参数或需要从Java(复杂对象,从属性文件或数据库读取的对象等)创建的参数,在testng.xml中指定参数可能不够。在这种情况下,您可以使用 数据提供程者 提供需要测试的值。数据提供者 是您的类上的一个方法,它返回对象数组。 此方法用@DataProvider注解:
//This method will provide data to any test method that declares that its Data Provider
//is named "test1"
@DataProvider(name = "test1")
public Object[][] createData1() {
return new Object[][] {
{ "Cedric", new Integer(36) },
{ "Anne", new Integer(37)},
};
}
//This test method declares that its data should be supplied by the Data Provider
//named "test1"
@Test(dataProvider = "test1")
public void verifyData1(String n1, Integer n2) {
System.out.println(n1 + " " + n2);
}
将打印
Cedric 36
Anne 37
@Test方法使用dataProvider属性指定其数据提供程者。 此名称必须与使用匹配名称@DataProvider(name =“…”)注解的同一类上的方法相对应。
默认情况下,将在当前测试类或其基类中查找数据提供者。 如果要将数据提供者放在不同的类中,则需要使用静态方法或具有non-arg构造函数的类,并指定可在dataProviderClass属性中找到的类:
public class StaticProvider {
@DataProvider(name = "create")
public static Object[][] createData() {
return new Object[][] {
new Object[] { new Integer(42) }
};
}
}
public class MyTest {
@Test(dataProvider = "create", dataProviderClass = StaticProvider.class)
public void test(Integer n) {
// ...
}
}
数据提供程者也支持注入。 TestNG将使用测试上下文进行注入。 数据提供者方法可以返回以下两种类型之一:
- 对象数组数组(Object [] []),其中第一个维度的大小是调用测试方法的次数,第二个维度大小包含必须与测试方法的参数类型兼容的对象数组。 这是上面的例子说明的。
- 一个迭代器
<Object []>
。 与Object [] []的唯一区别是,迭代器允许您慢慢创建测试数据。 TestNG将调用迭代器,然后使用该迭代器返回的参数逐个调用测试方法。 如果您有很多参数集要传递给方法,并且您不想预先创建所有参数集,这将非常有用。
下面就此功能举个例子:
@DataProvider(name = "test1")
public Iterator<Object[]> createData() {
return new MyIterator(DATA);
}
如果你声明的@DataProvider为一个java.lang.reflect.Method作为第一个参数,TestNG将为第一个参数传递当前的测试方法。(此处翻译可能不准确)。当几个测试方法使用相同的@DataProvider并且您希望它根据为其提供数据的测试方法返回不同的值时,这是特别有用的。
例如,以下代码在其@DataProvider中打印测试方法的名称:
@DataProvider(name = "dp")
public Object[][] createData(Method m) {
System.out.println(m.getName()); // print test method name
return new Object[][] { new Object[] { "Cedric" }};
}
@Test(dataProvider = "dp")
public void test1(String s) {
}
@Test(dataProvider = "dp")
public void test2(String s) {
}
结果:
test1
test2
属性数据提者可以与属性parallel并行运行:
@DataProvider(parallel = true)
// ...
默认情况下,从XML文件运行的并行数据提供者共享相同的线程池,其大小为10。 您可以在XML文件的标记中修改此值:
<suite name="Suite1" data-provider-thread-count="20" >
...
如果要在不同的线程池中运行几个特定的数据提供程序,则需要从不同的XML文件运行它们。
Parameters in reports
用于调用测试方法的参数显示在由TestNG生成的HTML报告中。 这里是一个例子:
Dependencies
有时,您需要以特定顺序调用您的测试方法。 这里有几个例子:
- 在运行更多测试方法之前,确保一定数量的测试方法已完成并成功。
- 初始化你的测试,同时希望这个初始化方法也是测试方法(用@ Before / After标记的方法不会成为最终报告的一部分)。
TestNG允许您使用注解或XML指定依赖性。
Dependencies with annotations
您可以使用属性dependsOnMethods或dependsOnGroups,在@Test注释中找到。
有两种依赖关系:
- 硬依赖。 所有依赖的方法都必须运行并成功运行。 如果您的依赖项中至少出现一个失败,则不会在报告中调用并标记为SKIP。
- 软依赖。 你将总是在依赖的方法之后运行,即使它们中的一些失败。 当你只想确保你的测试方法以一定的顺序运行时,这是有用的,但是它们的成功并不取决于他人的成功。 通过在@Test注释中添加“alwaysRun = true”可以获得软依赖。
这里是一个硬依赖的例子:
@Test
public void serverStartedOk() {}
@Test(dependsOnMethods = { "serverStartedOk" })
public void method1() {}
在这个例子中,method1()被声明为依赖于方法serverStartedOk(),它保证serverStartedOk()始终被首先调用。
您还可以具有依赖于整个组的方法:
@Test(groups = { "init" })
public void serverStartedOk() {}
@Test(groups = { "init" })
public void initEnvironment() {}
@Test(dependsOnGroups = { "init.*" })
public void method1() {}
在此示例中,method1()被声明为取决于与正则表达式“init.*”匹配的任何组,这保证在method1()之前始终调用serverStartedOk()和initEnvironment()方法。
注意:如前所述,属于同一组的方法的调用顺序不能保证在测试运行中是相同的。
如果一个方法依赖于失败,并且对它有一个硬依赖(alwaysRun = false,这是默认值),依赖它的方法不会被标记为FAIL,而是标记为SKIP。 跳过的方法将在最终报告中报告(在HTML中既不是红色也不是绿色),这是重要的,因为跳过的方法不一定是失败的。
有关依赖方法的更高级示例,请参阅 [本文]
其中为使用继承多个依赖关系的问题提供一个优雅的解决方案。
默认情况下,依赖方法按类分组。 例如,如果方法b()依赖于方法a(),并且您有几个包含这些方法的类的实例(因为数据提供者的工厂),那么调用顺序如下:
a(1)
a(2)
b(2)
b(2)
TestNG不会运行b(),直到所有实例都调用了他们的a()方法。
在某些情况下,这种行为可能不是期望的,例如测试针对各个国家的web浏览器的登录和退出。 在这种情况下,您需要以下顺序:
signIn("us")
signOut("us")
signIn("uk")
signOut("uk")
对于此排序,可以使用XML属性分组实例。 此属性在或上有效:
<suite name="Factory" group-by-instances="true">
or
<test name="Factory" group-by-instances="true">
Dependencies in XML
或者,您可以在testng.xml文件中指定组依赖关系。 您可以使用标记来实现:
<test name="My suite">
<groups>
<dependencies>
<group name="c" depends-on="a b" />
<group name="z" depends-on="c" />
</dependencies>
</groups>
</test>