dependency injection
Parameters with DataProviders
Specifying parameters in testng.xml might not be sufficient if you need to pass complex parameters, or parameters that need to be created from Java (complex objects, objects read from a property file or a database, etc...). In this case, you can use a Data Provider to supply the values you need to test. A Data Provider is a method on your class that returns an array of array of objects. This method is annotated with @DataProvider:
1 //This method will provide data to any test method that declares that its Data Provider 2 //is named "test1" 3 @DataProvider(name = "test1") 4 public Object[][] createData1() { 5 return new Object[][] { 6 { "Cedric", new Integer(36) }, 7 { "Anne", new Integer(37)}, 8 }; 9 } 10 11 //This test method declares that its data should be supplied by the Data Provider 12 //named "test1" 13 @Test(dataProvider = "test1") 14 public void verifyData1(String n1, Integer n2) { 15 System.out.println(n1 + " " + n2); 16 }
will print
1 Cedric 36 2 Anne 37
A @Test method specifies its Data Provider with the dataProvider attribute. This name must correspond to a method on the same class annotated with @DataProvider(name="...") with a matching name.
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 or a class with a non-arg constructor, and you specify the class where it can be found in the dataProviderClass attribute:
1 public class StaticProvider { 2 @DataProvider(name = "create") 3 public static Object[][] createData() { 4 return new Object[][] { 5 new Object[] { new Integer(42) } 6 }; 7 } 8 } 9 10 public class MyTest { 11 @Test(dataProvider = "create", dataProviderClass = StaticProvider.class) 12 public void test(Integer n) { 13 // ... 14 } 15 }
The data provider supports injection too. TestNG will use the test context for the injection. The Data Provider method can return one of the following two types:
- An array of array of objects (Object[][]) where the first dimension's size is the number of times the test method will be invoked and the second dimension size contains an array of objects that must be compatible with the parameter types of the test method. This is the cast illustrated by the example above.
- An Iterator<Object[]>. The only difference with Object[][] is that an Iterator lets you create your test data lazily. TestNG will invoke the iterator and then the test method with the parameters returned by this iterator one by one. This is particularly useful if you have a lot of parameter sets to pass to the method and you don't want to create all of them upfront.
Here is an example of this feature:
1 @DataProvider(name = "test1") 2 public Iterator<Object[]> createData() { 3 return new MyIterator(DATA); 4 }
Method参数
如果数据提供者的第一个参数是java.lang.reflect.Method,TestNG传递这个将调用的测试方法。如果您希望数据提供者根据不同的测试方法返回不同的数据,那么这种做法就非常有用。
If you declare your @DataProvider as taking a java.lang.reflect.Method as first parameter, TestNG will pass the current test method for this first parameter. This is particularly useful when several test methods use the same @DataProvider and you want it to return different values depending on which test method it is supplying data for.
For example, the following code prints the name of the test method inside its @DataProvider:
1 @DataProvider(name = "dp") 2 public Object[][] createData(Method m) { 3 System.out.println(m.getName()); // print test method name 4 return new Object[][] { new Object[] { "Cedric" }}; 5 } 6 7 @Test(dataProvider = "dp") 8 public void test1(String s) { 9 } 10 11 @Test(dataProvider = "dp") 12 public void test2(String s) { 13 }
and will therefore display:
1 test1 2 test2
TestNG lets you declare additional parameters in your methods. When this happens, TestNG will automatically fill these parameters with the right value. Dependency injection can be used in the following places:
- Any @Before method or @Test method can declare a parameter of type ITestContext.
- Any @AfterMethod method can declare a parameter of type ITestResult, which will reflect the result of the test method that was just run.
- Any @Before and @After methods can declare a parameter of type XmlTest, which contain the current <test> tag.
- Any @BeforeMethod (and @AfterMethod) can declare a parameter of type java.lang.reflect.Method. This parameter will receive the test method that will be called once this @BeforeMethod finishes (or after the method as run for @AfterMethod).
- Any @BeforeMethod can declare a parameter of type Object[]. This parameter will receive the list of parameters that are about to be fed to the upcoming test method, which could be either injected by TestNG, such as java.lang.reflect.Method or come from a @DataProvider.
- Any @DataProvider can declare a parameter of type ITestContext or java.lang.reflect.Method. The latter parameter will receive the test method that is about to be invoked.
You can turn off injection with the @NoInjection annotation:
1 public class NoInjectionTest { 2 3 @DataProvider(name = "provider") 4 public Object[][] provide() throws Exception { 5 return new Object[][] { { CC.class.getMethod("f") } }; 6 } 7 8 @Test(dataProvider = "provider") 9 public void withoutInjection(@NoInjection Method m) { 10 Assert.assertEquals(m.getName(), "f"); 11 } 12 13 @Test(dataProvider = "provider") 14 public void withInjection(Method m) { 15 Assert.assertEquals(m.getName(), "withInjection"); 16 } 17 }