Saturday, January 7, 2012

Bean Testing with JUnit

There are many areas we can test our software.  We have unit tests, integration tests,validation tests, load tests, acceptance tests, etc.  Here we use the JUnit testing framework to perform several tests on our application.  Because we have separated the view from the rest of the application, we can test the entire backend - the business layer, persistence layer, etc.  We can perform any test we wish and automate the verification / results.  This allows us to verify that each component performs as it is defined.  When we change the software, it is trivial to do a complete set of regression tests on the backend.  (The view portion we will test after finishing our discussion on JSF).

Now, just because the name of the framework is JUnit, does not mean that all the tests we write are unit tests.  The definition of a unit test is to test the smallest piece of an application that can be tested.  But, what if you want to test two pieces?  Well, no problem, we simply write an integration test.  Regardless of the type of test we wish to automate, testing the beans is easy and straightforward.  The only complicated portion would be with your application's logic - which needs to be completely exercised for correctness.

The example:  OrderEntityFacadeTest.java

package com.sample;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;


/**
 * @author Thomas Dias
 */
public class OrderEntityFacadeTest {
    private static EntityManagerFactory emf;
    private static EntityManager em;
    
    public OrderEntityFacadeTest() {
    }


    @BeforeClass
    public static void setUpClass() throws Exception {
        emf = Persistence.createEntityManagerFactory("localTestingPU");
    }


    @AfterClass
    public static void tearDownClass() throws Exception {
        emf.close();
    }
    
    @Before
    public void setUp() {
        em = emf.createEntityManager();
    }
    
    @After
    public void tearDown() {
        em.close();
    }


    @Test
    public void testCreateEditDelete() throws Exception {
        testCreate();
        em.clear();
        testEdit();
        em.clear();
        testRemove();
    }
    
    public void testCreate() throws Exception {
        System.out.println("create");
        OrderEntityFacadeInterface instance = (OrderEntityFacadeInterface) new OrderEntityFacade();
        instance.setEm(em);
        em.getTransaction().begin();
        instance.findAll();
        em.getTransaction().commit();
        em.clear();
        
        OrderEntity entity = new OrderEntity();
        entity.setName("TEST CREATE");
        PartEntity part = (PartEntity) instance.getEm().createQuery("select p from PartEntity p").getResultList().get(0);
        OrderPartsEntity orderParts = new OrderPartsEntity(entity, part, null);
        OrderPartsEntity subOrderParts = new OrderPartsEntity(entity, part, orderParts);
        OrderPartsEntity subOrderParts2 = new OrderPartsEntity(entity, part, subOrderParts);
        
        em.getTransaction().begin();
        instance.create(entity);
        em.getTransaction().commit();
        assertNotNull(entity.getId());
        OrderEntity result = instance.find(entity.getId());
        assertNotNull(result);
        assertTrue(result.getOrderedParts().size() > 0);
        assertTrue(result.getOrderedParts().get(0).getSubOrderParts().size() > 0);
        assertTrue(result.getOrderedParts().get(0).getSubOrderParts().get(0).getSubOrderParts().size() > 0);
    }


    public void testEdit() throws Exception {
        System.out.println("edit");
        OrderEntityFacadeInterface instance = (OrderEntityFacadeInterface) new OrderEntityFacade();
        instance.setEm(em);
        OrderEntity entity = (OrderEntity) em.createQuery("select o from OrderEntity o where name='TEST CREATE'").getResultList().get(0);
        em.clear();
        // load the full entity, could be a transaction so begin one
        em.getTransaction().begin();
        entity = instance.getOrderEntity(entity);
        em.getTransaction().commit();
        em.clear();
        
        entity.setName("EDIT TEST");
        entity.setCounter(5);
        em.getTransaction().begin();
        instance.edit(entity);
        em.getTransaction().commit();
        em.clear();


        OrderPartsEntity toremove = entity.getOrderedParts().get(0).getSubOrderParts().get(0);
        OrderPartsEntityFacade opef = new OrderPartsEntityFacade();
        opef.setEm(em);
        em.getTransaction().begin();
        opef.remove(toremove.getId());
        em.getTransaction().commit();
        em.clear();


        entity = (OrderEntity) em.createQuery("select o from OrderEntity o where name='EDIT TEST'").getResultList().get(0);
        assertNotNull(entity);
        assertNotNull(entity.getId());
        assertFalse(entity.getOrderedParts().isEmpty());
        assertTrue(entity.getOrderedParts().get(0).getSubOrderParts().isEmpty());
    }


    public void testRemove() throws Exception {
        System.out.println("remove");
        OrderEntityFacadeInterface instance = (OrderEntityFacadeInterface) new OrderEntityFacade();
        instance.setEm(em);


        OrderEntity entity = (OrderEntity) em.createQuery("select o from OrderEntity o where name='EDIT TEST'").getResultList().get(0);
        em.clear();
        em.getTransaction().begin();
        instance.remove(entity);
        em.getTransaction().commit();
        em.clear();
        List result = em.createQuery("select o from OrderEntity o where name='TEST CREATE'").getResultList();
        assertTrue(result.isEmpty());
    }
}


If you recall when we discussed our persistence setup, we had two persistence units. One we have been using through the container, the other was left for local usage.  In this test, we chose not to go through a JEE container and instead to handle the setup ourselves.  This we do by using the localTestingPU.  During our test setup, we create an EntityManagerFactory.  This will allow us to create and then inject an entity manager for the class we are going to test.  Don't forget to clean up in the after class for whatever you did in the before class.

Next we have the before test and after test methods that will be run before each test.  Here we create and close our EntityManager.

We then test our CRUD functions and verify they all work.  I'm not going to review the code as I believe it to be self explanatory, but as you can see, it was trivial to do a complete test of the Stateless bean.  One thing to note is that the way I wrote the tests did depend on a certain state of the database, so I required a particular order for the tests to run in.  Since JUnit does not guarantee order, I encapsulated the other tests in one test method called testCreateEditDelete() and called the other methods from there.

We can write tests for all our beans: Managed, CDI, EJB, and Entity beans, and they are no more complicated then the example above.  Some developers complain about creating tests, but I think you will find that writing your tests are not only simple, but decrease the amount of time required to debug your code.  During the course of creating this tutorial, I wrote several tests that I did not need to write simply because it is an effective debugging tool.  Once you have written the tests for debugging, you simply merge them into your testing suite and have even more code coverage.  Or, write the tests first and you debug through them to verify the accuracy of your code.

No comments:

Post a Comment