1.overview
TestNG is a testing framework inspired from JUnit and NUnit but introducing some new functionalities that make it more powerful and easier to use, such as:
- JDK 5 Annotations (JDK 1.4 is also supported with JavaDoc annotations).
- Support for data-driven testing (with @DataProvider ).
- Support for parameters.
- Embeds BeanShell for further flexibility.
- Default JDK functions for runtime and logging (no dependencies).
- Dependent methods for application server testing.
Here is a very simple test:
package example1;
import org.testng.annotations.*;
public class SimpleTest {
@BeforeClass
public void setUp() {
// code that will be invoked when this test is instantiated
}
@Test(groups = { "fast" })
public void aFastTest() {
System.out.println("Fast test");
}
@Test(groups = { "slow" })
public void aSlowTest() {
System.out.println("Slow test");
}
}
ant.xml
<project default="test">
<path id="cp">
<pathelement location="lib/testng-testng-4.4-jdk15.jar"/>
<pathelement location="build"/>
</path>
<taskdef name="testng" classpathref="cp"
classname="org.testng.TestNGAntTask" />
<target name="test">
<testng classpathref="cp" groups="fast">
<classfileset dir="build" includes="example1/*.class"/>
</testng>
</target>
</project>
Here is a quick overview of the annotations available in TestNG along with their attributes.
@BeforeSuite | Configuration information for a TestNG class: | |
| alwaysRun | For before methods (beforeSuite, beforeTest, beforeTestClass and beforeTestMethod, but not beforeGroups): If set to true, this configuration method will be run regardless of what groups it belongs to. |
| dependsOnGroups | The list of groups this method depends on. |
| dependsOnMethods | The list of methods this method depends on. |
| enabled | Whether methods on this class/method are enabled. |
| groups | The list of groups this class/method belongs to. |
| inheritGroups | If true, this method will belong to groups specified in the @Test annotation at the class level. |
| ||
@DataProvider | Marks a method as supplying data for a test method. The annotated method must return an Object[][] where each Object[] can be assigned the parameter list of the test method. The @Test method that wants to receive data from this DataProvider needs to use a dataProvider name equals to the name of this annotation. | |
| name | The name of this DataProvider. |
| ||
@Factory | Marks a method as a factory that returns objects that will be used by TestNG as Test classes. The method must return Object[]. | |
| ||
@Parameters | Describes how to pass parameters to a @Test method. | |
| value | The list of variables used to fill the parameters of this method. |
| ||
@Test | Marks a class or a method as part of the test. | |
| alwaysRun | If set to true, this test method will always be run even if it depends on a method that failed. |
| dataProvider | The name of the data provider for this test method. |
| dataProviderClass | The class where to look for the data provider. If not specified, the data provider will be looked on the class of the current test method or one of its base classes. If this attribute is specified, the data provider method needs to be static on the specified class. |
| dependsOnGroups | The list of groups this method depends on. |
| dependsOnMethods | The list of methods this method depends on. |
| description | The description for this method. |
| enabled | Whether methods on this class/method are enabled. |
| expectedExceptions | The list of exceptions that a test method is expected to throw. If no exception or a different than one on this list is thrown, this test will be marked a failure. |
| groups | The list of groups this class/method belongs to. |
| invocationCount | The number of times this method should be invoked. |
| invocationTimeOut | The maximum number of milliseconds this test should take for the cumulated time of all the invocationcounts. This attribute will be ignored if invocationCount is not specified. |
| successPercentage | The percentage of success expected from this method |
| sequential | If set to true, all the methods on this test class are guaranteed to run sequentially, even if the tests are currently being run with parallel="methods". This attribute can only be used at the class level and it will be ignored if used at the method level. |
| timeOut | The maximum number of milliseconds this test should take. |
| threadPoolSize | The size of the thread pool for this method. The method will be invoked from multiple threads as specified by invocationCount. |
3. Test groups
public class Test1 {
@Test(groups = { "functest", "checkintest" })
public void testMethod1() {
}
@Test(groups = {"functest", "checkintest"} )
public void testMethod2() {
}
@Test(groups = { "functest" })
public void testMethod3() {
}
}
Invoking TestNG with
<test name="Test1">
<groups>
<run>
<include name="functest"/>
</run>
</groups>
<classes>
<class name="example1.Test1"/>
</classes>
</test>
a test method or class could be unit test, dao test, regression test at the same time.
Here is another example, using regular expressions this time. Assume that some of your test methods should not be run on Linux, your test would look like:
@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() {
}
}
You could use the following testng.xml to launch only the Windows methods:
<test name="Test1">
<groups>
<run>
<include name="windows.*"/>
</run>
</groups>
<classes>
<class name="example1.Test1"/>
</classes>
</test>
Note: TestNG uses regular expressions , and not wildmats . Be aware of the difference (for example, "anything" is matched by ".*" -- dot star -- and not "*").
You can also exclude or include individual methods:
<test name="Test1">
<classes>
<class name="example1.Test1">
<methods>
<include name=".*enabledTestMethod.*"/>
<exclude name=".*brokenTestMethod.*"/>
</methods>
</class>
</classes>
</test>
You can define groups at the class level and then add groups at the method level:
@Test(groups = { "checkin-test" })
public class All {
@Test(groups = { "func-test" )
public void method1() { ... }
public void method2() { ... }
}
In this class, method2() is part of the group "checkin-test", which is defined at the class level, while method1() belongs to both "checkin-test" and "func-test".
@Parameters({ "first-name" })
@Test
public void testSingleString(String firstName) {
System.out.println("Invoked testString " + firstName);
assert "Cedric".equals(firstName);
}
<suite name="My suite">
<parameter name="first-name"
value="Cedric"/>
<test name="Simple example">
<-- ... -->
The same technique can be used for @Before/After and @Factory annotations:
@Parameters({ "datasource", "jdbcDriver" })
@BeforeMethod
public void beforeTest(String ds, String driver) {
m_dataSource = ...;
// look up the value of datasource
m_jdbcDriver = driver;
}
@Parameters("db")
@Test
public void testNonExistentParameter(@Optional("mysql") String db) { ... }
If no parameter named "db" is found in your testng.xml file, your test method will receive the default value specified inside the @Optional annotation: "mysql".
@DataProvider(name = "test1")
public Object[][] createData1() {
return new Object[][] {
{ "Cedric", new Integer(36) },
{ "Anne", new Integer(37)},
};
}
@Test(dataProvider = "test1")
public void verifyData1(String n1, Integer n2) {
System.out.println(n1 + " " + n2);
}
will print
Cedric 36
Anne 37
@Test(dataProvider = "test1",invocationCount=3)
public void verifyData1(String n1, Integer n2) {
System.out.println(n1 + " " + n2);
}
Total tests run: 6, Failures: 0, Skips: 0
By default, the data provider will be looked for in the current test class or one of its base classes. If you want to put your data provider in a different class, it needs to be a static method and you specify the class where it can be found in the dataProviderClass attribute:
public static 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) {
// ...
}
}
ps. StaticProvider 类 不一定必须是static, 方法必须是static
dataprovider提供的是一个二维数组,只算count一次
new Object[][] {
{ "Cedric", new Integer(36) }, 一组测试数据
{ "Anne", new Integer(37)},
一组测试数据
};
@DataProvider(parallel = true)
dependent on method
@Test
public void serverStartedOk() {}
@Test(dependsOnMethods = { "serverStartedOk" })
public void method1() {}
dependent on group
@Test(groups = { "init" })
public void serverStartedOk() {}
@Test(groups = { "init" })
public void initEnvironment() {}
@Test(dependsOnGroups = { "init.* })
public void method1() {}
public class WebTestFactory {
@Factory
public Object[] createInstances() {
Object[] result = new Object[10];
for (int i = 0; i < 10; i++) {
result[i] = new WebTest(i * 10);
return result;
}
}
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
}
}
}
@Test(threadPoolSize = 3, invocationCount = 10,
timeOut = 10000)
public void testServer() {
java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -d test-outputs testng.xml
java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -d test-outputs test-outputs\testng-failed.xml