Spring Dependency Injection in Mule FunctionalTestCase

By | December 13, 2015

In this article I will show how to accomplish dependency injection of fields in tests that inherit from the Mule class FunctionalTestCase; both of dependencies to Spring beans and of values from property files.

Background

On an earlier occasion, I have attempted to use the standard @RunWith(SpringJUnit4ClassRunner.class) annotation in order to be able to have Spring inject dependencies into my tests. This works very well as long as your test-class does not inherit from the Mule FunctionalTestCase class.
Instead I have had to rely on writing code to retrieve dependencies and configuration property values in such tests.
In Mule 3.7 the Mule registry has been unified  and now all Spring beans (i.e. objects, but I have never seen anyone use anything but Spring as the DI container in Mule) can be found in one and the same registry.

Attempt with Null

Let’s get down to business, that is the code. This is how I would like to be able to write a Mule test based on the class FunctionalTestCase:

package se.ivankrizsan.mule.springditest;

import org.junit.Test;
import org.mule.tck.junit4.FunctionalTestCase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;

/**
 * Example Mule functional test case with Spring autowiring and injection of values from properties file.
 *
 * @author Ivan Krizsan
 */
public class TestSpringDIWithMuleFunctionalTestCase extends FunctionalTestCase {
    /* Constant(s): */

    /* Instance variable(s): */
    @Value("${WEBPAGE_URL}")
    protected String mWebpageUrl;
    @Value("${RETRY_COUNT}")
    protected Integer mRetryCount;
    @Autowired
    @Qualifier("ivanPerson")
    protected Person mIvanPerson;


    @Override
    protected String getConfigFile() {
        return "src/main/app/mule-config.xml";
    }

    @Test
    public void testDependencyInjection() throws Exception {
        System.out.println("Webpage URL: " + mWebpageUrl);
        System.out.println("Retry count: " + mRetryCount);
        System.out.println("Person bean: " + mIvanPerson);
        if (mIvanPerson != null) {
            System.out.println("Person bean name: " + mIvanPerson.getName());
        }
    }
}

Worth mentioning is that I have a properties file with the following contents:

# Configuration properties for the example Mule application.
WEBPAGE_URL=https://www.ivankrizsan.se
RETRY_COUNT=10

However, if we run the above test, the following will be printed to the console:

Webpage URL: null
Retry count: null
Person bean: null

A New Test Class

How does Spring accomplish dependency injection of fields annotated with, for instance, @Autowired?
Some research led me to the AutowiredAnnotationBeanPostProcessor class in Spring. In that class I even found a method named processInjection which sounded just right! Some research into Mule’s FunctionalTestCase and its parent classes led me to decide that the doSetUp method seems like a suitable place to perform dependency injection of the test instance. Armed with this knowledge, I wrote a new parent-class for my Mule tests:

package se.ivankrizsan.mule.springditest;

import org.mule.api.registry.RegistrationException;
import org.mule.api.registry.Registry;
import org.mule.tck.junit4.FunctionalTestCase;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;

/**
 * Mule functional test case that will perform Spring dependency injection on the test class instance
 * prior to executing tests.
 * For dependency injection to be performed, the Mule context must be started before the {@code doSetUp}
 * method is executed.
 * For details on dependency injection performed, please refer to {@code AutowiredAnnotationBeanPostProcessor}.
 *
 * @author Ivan Krizsan
 * @see AutowiredAnnotationBeanPostProcessor
 */
public abstract class SpringDIFunctionalTestCase extends FunctionalTestCase {

    @Override
    protected void doSetUp() throws RegistrationException {
        if (muleContext.isStarted()) {
            final Registry theRegistry = muleContext.getRegistry();
            final AutowiredAnnotationBeanPostProcessor theAutowiredAnnotationBeanPostProcessor;
            try {
                theAutowiredAnnotationBeanPostProcessor =
                    theRegistry.lookupObject(AutowiredAnnotationBeanPostProcessor.class);
            } catch (final RegistrationException theException) {
                logger.error("An error occurred retrieving AutowiredAnnotationBeanPostProcessor", theException);
                throw theException;
            }

            if (theAutowiredAnnotationBeanPostProcessor != null) {
                theAutowiredAnnotationBeanPostProcessor.processInjection(this);
            } else {
                logger.warn("No AutowiredAnnotationBeanPostProcessor in the Mule registry, "
                    + "could not perform dependency injection on the test instance.");
            }
        } else {
            logger.warn("Mule context is not started, no dependency injection on test instance performed.");
        }
    }
}

I added some checks and warning logs, in case the necessary prerequisites are not met or a plain error occurs.

Attempt with the New Test Class

If I now change the parent class of my test class shown earlier from FunctionalTestCase to SpringDIFunctionalTestCase and run it, the following is printed on the console:

Webpage URL: https://www.ivankrizsan.se
Retry count: 10
Person bean: se.ivankrizsan.mule.springditest.Person@32413e99
Person bean name: Ivan Krizsan

Success!

The complete example project is available on GitHub.
Happy coding!

 

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *