Monday, March 17, 2014

Dependency Injections in Java interview Questions

 Dependency injection

TestNG supports two different kinds of dependency injection: native (performed by TestNG itself) and external (performed by a dependency injection framework such as Guice).
5.18.1 - Native dependency injection
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");
  }
}
5.18.2 - Guice dependency injection
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. What is dependency injection?

The general concept behind dependency injection is called Inversion of Control. A class should not configure its dependencies statically but should be configured from outside.
Dependency injection is a concept which is not limited to Java. But we will look at dependency injection from a Java point of view.
A Java class has a dependency on another class if it uses an instance of this class. For example a class which accesses a logger service has a dependency on this service class.
Ideally Java classes should be as independent as possible from other Java classes. This increases the possibility of reusing these classes and to be able to test them independently from other classes.
If the Java class directly creates an instance of another class via the new operator, it cannot be used (and tested) independently from this class and this is called a hard dependency. The following example shows a class which has no hard dependencies.

package com.example.e4.rcp.todo.parts;

import java.util.logging.Logger;

import org.eclipse.e4.core.services.events.IEventBroker;

public class MyClass {
  
  Logger logger;
  
  public MyClass(Logger logger) {
    this.logger = logger;
    // write an info log message
    logger.info("This is a log message.")
  }
} 

Note

Please note that this class is just a normal Java class, there is nothing special about it, except that it avoids direct object creation.
Another class could analyze the dependencies of a class and create an instance of the class, injecting objects into the defined dependency. This can be done via the Java reflection functionality by a framework class usually called the dependency container.
This way the Java class has no hard dependencies, which means it does not rely on an instance of a certain class. This allows you to test your class in isolation, for example by using mock objects.
Mock objects are objects, which act as if they are the real object, but only simulate their behavior. Mock is an English word which means to mimic or imitate.
If dependency injection is used, a Java class can be tested in isolation.

2. Using annotations to describe dependencies

In general different approaches exist to describe the dependencies of a class. The most common approach is to use Java annotations to describe the dependencies directly in the class.
The standard Java annotations for describing dependencies were defined in the Java Specification Request 330 (JSR330). This specification describes the @Inject and @Named annotations.
To decouple Java classes, its dependencies should be fulfilled from the outside. A Java class would simply define its requirements like in the following example:

public class MyPart {

  // import statements left out

  
  @Inject private Logger logger;
  
  // inject class for database access
  @Inject private DatabaseAccessClass dao;
  
  @Inject
  public void createControls(Composite parent) {
    logger.info("UI will start to build");
    Label label = new Label(parent, SWT.NONE);
    label.setText("Eclipse 4");
    Text text = new Text(parent, SWT.NONE);
    text.setText(dao.getNumber());
  }

} 

Note

Please note that this class uses the new operator for the user interface components. This implies that this part of the code is nothing you plan to replace via your tests and that you made the decision to have a hard coupling to the corresponding user interface toolkit.

3. Where can values be injected?

Dependency injection can be performed on:
  • the constructor of the class (construction injection)
  • a field (field injection)
  • the parameters of a method (method injection)

Dependency injection can be performed on static and on non-static fields and methods.

Tip

Avoid using dependency injection for statics as this typically leads to confusion and has the following restrictions:
  • Static fields will be injected after the first object of the class was created via DI, which means not to access the static field in the constructor
  • Static fields should not be marked as final, otherwise the compiler complains about them
  • Static methods are called only once after the first object of the class was created

4. Order in which injection is done

According to JSR330 the injection is done in the following order:
  • constructor injection
  • field injection
  • method injection

The order in which the methods or fields annotated with @Inject are called is not defined by JSR330. You cannot assume that the methods or fields are called in the order of declaration in the class.

Warning

As fields and methods parameters are injected after the constructor is called, you cannot use injected member variables in the constructor.

5. Java and dependency injection frameworks

You can use dependency injection without any additional framework by providing classes with sufficient constructors or getter and setter methods.
A dependency injection framework simplifies the initialization of the classes with the correct objects.
Two popular dependency injection frameworks are Spring and Google Guice.
The usage of the Spring framework for dependency injection is described in Dependency Injection with the Spring Framework - Tutorial.

3 comments:

  1. Is there a example with Automation framework where dependency injection works?

    ReplyDelete
  2. Great article Lot's of information to Read...Great Man Keep Posting and update to People..Thanks Ozempic Injections

    ReplyDelete

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...