Thursday, December 11, 2014

Dependency Injection in TestNG



TestNG supports two different kinds of dependency injection: native (performed by TestNG itself) and external (performed by a dependency injection framework such as Guice).
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:
public class NoInjectionTest {


  @DataProvider(name = "provider")
  public Object[][] provide() throws Exception {

      return new Object[][] { { CC.class.getMethod("f") } };
  }


  @Test(dataProvider = "provider")

  public void withoutInjection(@NoInjection Method m) {
      Assert.assertEquals(m.getName(), "f");

  }


  @Test(dataProvider = "provider")
  public void withInjection(Method m) {

      Assert.assertEquals(m.getName(), "withInjection");
  }

}
If you use Guice, TestNG gives you an easy way to inject your test objects with a Guice module:
@Guice(modules = GuiceExampleModule.class)
public class GuiceTest extends SimpleBaseTest {


  @Inject

  ISingleton m_singleton;


  @Test
  public void singletonShouldWork() {

    m_singleton.doSomething();
  }


}
In this example, GuiceExampleModule is expected to bind the interface ISingleton to some concrete class:
public class GuiceExampleModule implements Module {


  @Override
  public void configure(Binder binder) {

    binder.bind(ISingleton.class).to(ExampleSingleton.class).in(Singleton.class);
  }


}
If you need more flexibility in specifying which modules should be used to instantiate your test classes, you can specify a module factory:
@Guice(moduleFactory = ModuleFactory.class)
public class GuiceModuleFactoryTest {


  @Inject

  ISingleton m_singleton;


  @Test
  public void singletonShouldWork() {

    m_singleton.doSomething();
  }

}
The module factory needs to implement the interface IModuleFactory:
public interface IModuleFactory {
 /**

   * @param context The current test context
   * @param testClass The test class

   *
   * @return The Guice module that should be used to get an instance of this

   * test class.
   */

  Module createModule(ITestContext context, Class<?> testClass);
}
Your factory will be passed an instance of the test context and the test class that TestNG needs to instantiate. Your createModule method should return a Guice Module that will know how to instantiate this test class. You can use the test context to find out more information about your environment, such as parameters specified in testng.xml, etc...

1 comment:

TestNG - Can i use the 2 different data providers to same @test methods in TestNG?

public Object [][] dp1 () { return new Object [][] { new Object [] { "a" , "b" }, new Obje...