Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing EJB 3.1

I am doing a small research on Unit Testing of EJB 3.1. At the end my goal is to produce a easy to use solution for Unit Testing EJB 3.1.

  1. I do not have much knowledge with big EJB implementations and hence I would like to first get some experienced hands (You) to just pool in your ideas on what is difficult in Unit Testing EJBs.
  2. With the initial research I have already done, I can understand the advantages of using mocking frameworks for Unit Testing rather than using embedded containers. Though both are good, mocking frameworks stands a little above when it comes to Unit Testing. The embedded containers are ofcourse very good and have their own advantages, but may be a different phase of unit testing. I still believe that there should be some shortfalls at least in some scenarios in using such frameworks which can be improved.

I hope I could make a complete solution for Unit Testing EJB which I can share in this forum once done.

Thanks for your support.

like image 798
Bala Avatar asked Oct 14 '11 09:10

Bala


3 Answers

My advice to you would be to not fall into the common trap I see, which is to think you need to chose between mocking and using an embedded EJB container.

You can use both, you should use both, and where you find it difficult to use both you should demand better support and more features from your EJB container.

Certainly, you will find people at OpenEJB really supportive and more than happy to add features to support getting the best of both worlds. Nearly all the really good features have been created around the requests of users trying to do very specific things and finding it hard.

Standard EJBContainer API

package org.superbiz.stateless.basic;

import junit.framework.TestCase;

import javax.ejb.embeddable.EJBContainer;

public class CalculatorTest extends TestCase {

    private CalculatorBean calculator;

    /**
     * Bootstrap the Embedded EJB Container
     *
     * @throws Exception
     */
    protected void setUp() throws Exception {

        EJBContainer ejbContainer = EJBContainer.createEJBContainer();

        Object object = ejbContainer.getContext().lookup("java:global/simple-stateless/CalculatorBean");

        assertTrue(object instanceof CalculatorBean);

        calculator = (CalculatorBean) object;
    }

Full source here

This scans the classpath and loads all beans.

No-scanning, easier mocking approach

Slightly different approach where you define everything in code. Obviously mocking is easier as you can supply mock implementations of beans where needed at will.

@RunWith(ApplicationComposer.class)
public class MoviesTest extends TestCase {

    @EJB
    private Movies movies;

    @Resource
    private UserTransaction userTransaction;

    @PersistenceContext
    private EntityManager entityManager;

    @Module
    public PersistenceUnit persistence() {
        PersistenceUnit unit = new PersistenceUnit("movie-unit");
        unit.setJtaDataSource("movieDatabase");
        unit.setNonJtaDataSource("movieDatabaseUnmanaged");
        unit.getClazz().add(Movie.class.getName());
        unit.setProperty("openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)");
        return unit;
    }

    @Module
    public EjbJar beans() {
        EjbJar ejbJar = new EjbJar("movie-beans");
        ejbJar.addEnterpriseBean(new StatefulBean(MoviesImpl.class));
        return ejbJar;
    }

    @Configuration
    public Properties config() throws Exception {
        Properties p = new Properties();
        p.put("movieDatabase", "new://Resource?type=DataSource");
        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
        return p;
    }

    @Test
    public void test() throws Exception {

        userTransaction.begin();

        try {
            entityManager.persist(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
            entityManager.persist(new Movie("Joel Coen", "Fargo", 1996));
            entityManager.persist(new Movie("Joel Coen", "The Big Lebowski", 1998));

            List<Movie> list = movies.getMovies();
            assertEquals("List.size()", 3, list.size());

            for (Movie movie : list) {
                movies.deleteMovie(movie);
            }

            assertEquals("Movies.getMovies()", 0, movies.getMovies().size());

        } finally {
            userTransaction.commit();
        }
    }
}

Full source here

The end result

It's tempting to focus on the differences between different types of testing, etc. but certainly there's something to be said for a pragmatic middle. I personally don't see anything wrong with being able to mix "unit" and "integration" styles as fluently as possible.

Certainly, it's an admirable goal. Ideas and feature requests to get us closer are very welcome.

like image 148
David Blevins Avatar answered Oct 19 '22 04:10

David Blevins


There are actually two different types of testing you might want to consider (not exclusive):

  • Unit Testing: Your EJBs are POJOs at the end of the day and therefore you can use your preferred unit testing framework (e.g. JUnit) and also a mocking framework like Mockito or EasyMock.
  • Integration testing: here you want to test the EJBs as if they were in the container (not in isolation) and therefore you have to somehow emulate that container. You can still use your unit testing framework to code your tests (e.g. JUnit), but now you are testing how these EJBs behave in the container and interact with other collaborators (e.g. other EJBs) they might have. For this I would recommend Arquillian
like image 20
Gonzalo Garcia Lasurtegui Avatar answered Oct 19 '22 02:10

Gonzalo Garcia Lasurtegui


You can use Needle for unit tests of Java EE components.

Needle is a lightweight framework for testing Java EE components outside of the container in isolation. It reduces the test setup code by analysing dependencies and automatic injection of mock objects.

http://needle.spree.de

like image 3
Heinz Avatar answered Oct 19 '22 02:10

Heinz