Unit Testing EJB3 Beans

23rd December, 2010 Patrick

When we first started unit testing our EJB3 Stateless Session beans we ran into the problem on how to inject mocked objects into objects that were under test. There were a couple of techniques that attempted such as adding setters, which we didn't like because there was no way to prevent someone from calling them during production. The second option was to create a constructor with all the dependencies which solved the setter problem but this would require a lot more work since some beans could have ten or more dependencies.

The solution that worked best for us was inject the beans manually using refection. I built a small utility class to accomplish this and had evolved overtime to what it is today.

import java.lang.reflect.Field;

public class BeanUtil {

    /**
     * Attempts to inject a dependency into a object that doesn't have setter
     * methods or constructors to do so. This will search for the first field
     * that matches the dependency type.
     * 
     * @param bean
     *            The object that needs a dependency injected into
     * @param dependency
     *            The object that fulfills the required dependency
     * @throws NoSuchFieldException
     */
    public static void inject(Object bean, Object dependency)
            throws NoSuchFieldException {
        // since no field name was given we will look for the field via type
        Field[] fields = bean.getClass().getDeclaredFields();
        String fieldName = null;
        for (Field field : fields) {
            if (field.getType().isInstance(dependency)) {
                fieldName = field.getName();
                break;
            }
        }

        // check to make sure we found a field
        if (fieldName == null) {
            throw new NoSuchFieldError("Unable to locate a field in "
                    + bean.getClass().getName() + " that is an instance of "
                    + dependency.getClass().getName());
        }
        inject(bean, dependency, fieldName);
    }

    /**
     * Attempts to inject a dependency into a object that doesn't have setter
     * methods or constructors to do so. This method should be used when you
     * have two fields of the same type.
     * 
     * @param bean
     *            The object that needs a dependency injected into
     * @param dependency
     *            The object that fulfills the required dependency
     * @param fieldName
     *            Name of the field that the dependency should be injected to.
     * @throws NoSuchFieldException
     */
    public static void inject(Object bean, Object dependency, String fieldName)
            throws NoSuchFieldException {
        // find filed and inject dependency
        Field field = bean.getClass().getDeclaredField(fieldName);
        boolean accessible = field.isAccessible();
        field.setAccessible(true);
        try {
            field.set(bean, dependency);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Should not happen since we changed "
                    + "the accessibility of the object to public", e);
        }
        field.setAccessible(accessible);
    }

    /**
     * Attempts to inject a dependencies into a object that doesn't have setter
     * methods or constructors to do so. This will search for the first field
     * that matches the dependency type.
     * 
     * @param bean
     *            The object that needs a dependency injected into
     * @param dependencies
     *            Objects that fulfills the required dependencies
     * @throws NoSuchFieldException
     */
    public static void inject(Object bean, Object... dependencies)
            throws NoSuchFieldException {
        for (Object dependency : dependencies) {
            inject(bean, dependency);
        }
    }
}

Then to use it you can either static import the BeanUtil class or just call BeanUtil.inject()