Friday, February 21, 2014

UnitTesting in JavaEE

In this post, i want to show how to implemented UnitTests for a Java EE Application, how to test some Methods of a BackingBean which has Dependencies on other Resources (EJB's, POJO's, etc.).
Unit Tests are meant for testing single Methods of a Class only, without any other resources. Integration Tests, on the other hand, are meant for tests which include interaction between different resources (DataBase, Dependencies, etc.). Most Classes used in a Java EE Environment use other Classes with Dependency Injection.
Mockito is perfect for mocking / simulating that other resources, like Database access, etc. One "problem" with unit tests, in general, is that how to access fields marked with a private modifier and no setter. If you don't want to change the original class by using protected instead of private modifiers or add setter Methods, you can do your own DI by using the Java Reflection API.
Say you have a Backing Bean called ArticleModel which has a Dependency on another EJB Stateless Session Bean called ArticleService. The Backing Bean has a Method get ArticlePreview which returns a List of Strings with just the 1st 200 characters of all article text formatted with some HTML. The Article Model uses the injected EJB ArticleService to retrieve all Article Entities from the Database, iterates through them, abbreviates the Article Text of each Article and adds some HTML Tags.
To implement a Unit Test we now need a Mock for ArticleService, because we don’t have a DatabaseConnection. Also, we have to inject the Mock somehow into the ArticleModel Class because we don’t have DI in Unit Tests.

First lets take a look at the ArticleModel Class:
public class ArticleModel {  
      
      //The Stateless Session bean which interacts with the DB
      @Inject 
      private ArticleService articleService;  
      
      public List<String> getAllArticlePreviews() {
         List<String> previews = new ArrayList<String>();
         for(ArticleEntity article : articleService.findAllArticles()) {
            String t = article.getText();
            t = t.substring(193);
            t = "<i>" + t + "<&#47i>";
            previews.add(t);
         }
         return previews;
      }
  
 }   
Now the ArticleService Class:
@Stateless
public class ArticleService {  
      
      @PersistenceContext(name = "persistenceUnitName") 
      EntityManager em;  
      
      public List<ArticleEntity> findAllArticles() {
         try {
            return em.createQuery("select a from Article a", ArticleEntity.class).getResultList();
         } catch (Exception e) {
            // log
            return null;
         }
      }
  
 }   
Let's now create a Unit Test for the ArticleModel, a simple Test Class which keeps an instance of the ArticleModel, calls it's Methods and make some checks.
The ArticleModelTest Class could look like this:
public class ArticleModelTest {  

      //The class to be tested
      private ArticleModel articleModel;

      @Before
      public void setUp() {
         articleModel = new ArticleModel();
      }

      //the actual unit test
      @Test
      public void testGetAllArticlePreviews() throws Exception {
         List previews = articleModel.getAllArticlePreviews();
         for(String preview : previews) {
            //simply test if preview text is not bigger than 200 chars
            Assert.assertTrue(preview.length() <= 200);
            ...
         }
      }
  
 }   
The above code will not work as it is, because articleModel depends on the ArticleService class which will be injected by CDI when deployed in JavaEE. When running the test it is null. Therefore we have to do 2 things. First is to setup a Mock for ArticleService which returns "dummy" Data. Then this mock needs to be injected into the ArticleModel.
The ArticleModelTest Class extended with Mockito and custom DI:

import org.mockito.Mock;
import static org.mockito.Mockito.when;
import org.mockito.MockitoAnnotations;

public class ArticleModelTest {  
      
      //The Mock for ArticleService
      @Mock ArticleService articleService;

      //The class to be tested
      private ArticleModel articleModel;
      
      @Before
      public void setUp() throws Exception {
         
         //needed for Mockito
         MockitoAnnotations.initMocks(this)
         //custom DI - inject the articleService into ArticleModel
         Class clazz = Class.forName("foo.bar.ArticleModel");
         articleModel = (ArticleModel) clazz.newInstance();
         Field[] fields = clazz.getDeclaredFields();
         for (Field f : fields) {
            /**
            * the field articleService is private, 
            * to inject it we have to set it accessible 
            */
            f.setAccessible(true); 
            if (f.getName().equals("articleService")) {
                //inject the articleService into articleModel
                f.set(articleModel, articleService);
            }
        }
      }

      //the actual unit test
      @Test
      public void testGetAllArticlePreviews() throws Exception {
 
         /**
         * create a list with "dummy" ArticleEntities 
         * which should be returned when ArticleModel 
         * calls the ArticleService.findAllArticles() Method
         */
         List<ArticleEntity> articles = new ArrayList<ArticleEntity&gt();
         articles.add(new ArticleEntity("xxx"));
         ...
         articles.add(new ArticleEntity("yyy"));
         
         /**
         * this is to tell Mockito that our created list 
         * should be returned whenever findAllArticles() is called
         */
         when(articleService.findAllArticles()).thenReturn(articleList);

         List<String> previews = articleModel.getAllArticlePreviews();
         for(String preview : previews) {
            //simply test if preview text is not bigger than 200 chars
            Assert.assertTrue(preview.length() <= 200);
            ...
         }
      }
  
 }   
now the Unit Test will work!

Thursday, January 3, 2013

Inject EJBs into non ejb-jar's

When CDI is enabled (existing beans.xml in resources/META-INF), all EJBs of a *.war or *.ear can be injected with the @Inject Annotation (JSR 330).
The Injection Point can be defined in any Java Class, not only EJBs, because all classes are Managed Beans when CDI is enabled. So far that works fine, but not for Classes packed as a .jar under /lib.
The Problem occurred while implementing a plugin solution for a *.ear packaged project.

Plugin:
 public class PluginA implements IPlugin {  
   
      @Inject SomeClass anotherPOJO; //works fine  
      @Inject SomeService someStatelessEJB; //doesn't work  
 …  
 }   

By the way, defining replaceable Plugins can be easily done with @Inject @Any javax.enterprise.inject.Instance<T>, where the CDI Container locates all Implementations and injects them in the javax.enterprise.inject.Instance Object, which offers an Iterator to loop through all Plugins found. The same can be achieved by injecting the javax.enterprise.inject.spi.BeanManager and iterate through the Set of Beans (Bean<T>) returned from its getBeans() Method, passing either the EL Name (String based Qualifier) or Type and Qualifier.  

Because the Plugins don't need any Container Managed Transaction or Security, defining them as EJBs (@Stateless, Stateful or @Singleton) would not bring any advantage, so they are implemented as POJOs and packed as plain .jar files under /lib. 
Now, all CDI Managed Beans can be injected in the Plugin Implementations, but it doesn't work for EJBs like that. The EJB DI only works for Classes inside an ejb-jar or *.war. but not for POJOs located in a .jar file under /lib.
To inject EJBs nevertheless i wrote a Factory Class with Producer Method which does a JNDI lookup for the desired EJB and returns it.

EJBFactory:
 public class EJBFactory {  
   
    String jndi =   
    "java:global/myApp/myModule/"  
    + "SomeServiceImpl!com.foo.SomeService";  
   
    @Produces  
    public SomeService getSomeService() {  
      try {  
         Context c = new InitialContext();  
         return (SomeService) c.lookup(jndi);  
      } catch (NamingException e) {  
         //log  
      } catch(ClassCastException ce) {  
         //log  
      }  
      return null;  
    }  
 …  
 }  

Note:
The Producer Method can also throw a checked Exception (in case the lookup or Casting failed -> throws NamingException, ClassCastException) which will be caught by the CDI Container and re thrown as javax.enterprise.inject.CreationException, which then will cause an abortion of the Deployment. I decided to just return null and check that when the Service is actually needed to avoid Exceptions during Deployment.

With that Factory, located anywhere inside the Application, directly or also as a *.jar packed lib, the EJB will be injected using @Inject SomeService someStatelessEJB;
To avoid Ambiguous Dependencies Issues when Injecting the EJBs also outside of the Plugins, a Qualifier is needed. 
Let me explain that a little more detailed. 
The SomeService Interface is Implemented by an EJB (@Stateless) and used also inside the Application. It is Injected in other EJBs or POJOs with @Inject, and that works fine because the InjectionPoints are located inside an *.ear or .*war. When the EJBFactory also offers a Producer Method for SomeService Injection, the CDI Container finds 2 Dependencies for that SomeService Type, one is the actually implemented SomeServiceImpl (not available for the Plugins) and the other Dependency is the EJBFactory's Producer Method. To solve that we simply need to add an Qualifier to the Producer Method to be able to differentiate between them.

The Qualifier is defined as Annotation annotated with @Qualifier and looks like this:

Qualifier:
 @Qualifier  
 @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})  
 @Retention(RetentionPolicy.RUNTIME)  
 public @interface EJBResource {}  

Now the Qualifier has to be used for both, the Producer Method and the Plugins InjectionPoints.

Extend the EJBFactory:
 
public class EJBFactory {  
   
    String jndi =   
    "java:global/myApp/myModule/"  
    + "SomeServiceImpl!com.foo.SomeService";  
   
    @Produces  
    @EJBResource
    public SomeService getSomeService() {  
      try {  
         Context c = new InitialContext();  
         return (SomeService) c.lookup(jndi);  
      } catch (NamingException e) {  
         //log  
      } catch(ClassCastException ce) {  
         //log  
      }  
      return null;  
    }  
 …  
 }  

and the Plugin:
 public class PluginA implements IPlugin {  
   
      @Inject SomeClass anotherPOJO; //works fine  
      @Inject @EJBResource SomeService someStatelessEJB; //works now  
 …  
 }   

Thats all!