Unit-testing Mule transformers which access session and/or invocation scopes

By | July 4, 2013

Problem

When attempting to unit-test a Mule transformer that need access to session- or invocation-scoped message properties, I found the result to be an IllegalStateException that told me:

Detected an attempt to set an invocation or session property, but a MuleEvent hasn’t been created using this message yet.

I managed to trace the problem to the MessagePropertiesContext class, where I could see that the maps holding the session- and invocation-scoped message properties are created using two classes with names that, in a way, revealed their purpose, namely UndefinedSessionPropertiesMap and UndefinedInvocationPropertiesMap.

I made one attempt at testing such transformers, but was not entirely happy with it. This post describes my second attempt, which I feel more content with.
The technique described here has been tested on Mule Community Edition 3.3 and 3.4, but is expected to work under any 3.x version of Mule.

UPDATE July 27, 2016
The example in this article has been updated to run on Mule CE 3.7 and 3.8. It requires minor modifications to run on earlier 3.x version of Mule CE.

A Mule Transformer

I needed a Mule transformer to test, so I implemented MyTransformer:

Note that:

  • The transformer class inherits from AbstractMessageTransformer.
    In order to be able to access message properties in the transformer, the transformer need to receive the entire Mule message to transform, not just the message payload.
  • The transformer sets two message properties; one in the session scope and another in the invocation scope.

A New, Better Message

When testing a Mule transformer that needs to use one or more message property scopes, we will need to send it a Mule message as discussed above.
Examining the DefaultMuleMessage class, we can see a properties instance variable of the type MessagePropertiesContext.
MessagePropertiesContext is the class that contains the maps that hold the invocation- and session-scoped message properties. In order for my transformer unit test not to cause an exception to be thrown, these maps need to be replaced with instances of, for instance, HashMap. Fortunately, there are two methods in that allows us to do that in the DefaultMuleMessage class, namely setSessionProperties and setInvocationProperties. Less fortunate is the fact that both these methods only have package-visibility.

The trick I use is to create a subclass of DefaultMuleMessage in the same package, namely org.mule, that looks like this:

The implementation of DefaultTestMuleMessage just adds a call to a method that initialize the maps holding the session- and invocation-scoped message properties in each constructor.

Transformer Test Base Class

Having implemented the DefaultTestMuleMessage class is not enough for me, I want it to be as convenient as possible to implement Mule transformer unit tests.
I implemented the following class, based on the Mule test-class AbstractMuleContextTestCase, with the following motivations:

  • Availability of a Mule context.Mule messages cannot be created without a Mule context being available.
    The context can be empty, as in this case.
  • Automatic creation of a Mule message to be sent to the transformer under test prior to each test method.
  • Easy configuration of the Mule message to be sent to the transformer.
    The Mule message is created using the Template Method design pattern, which allows subclasses to override the implementation of one or both of the methods that create the Mule message and that prepares the Mule message by setting payload and message properties on the message. Overriding of the former method is expected to happen less often.

The transformer test base class looks like this:

Note that:

  • The class MuleTransformerUnitTestCase is abstract.
    It is expected that each transformer unit test will create a subclass of this class.
  • There is an instance variable mTestMessage.
    Before execution of each test method in the subclass, this instance variable will hold a reference to a new Mule message that is to be the input to the transformer under test.
  • The constructor sets the disposeContextPerClass instance variable in the superclass to true.
    The consequence of this is that only one single Mule context will be created for all the test methods in a subclass of this class. The reason for creating just one single Mule context for all test methods and not one for each test method is to reduce the execution time of test classes inheriting from this class.
  • There is a createTestMessageBeforeEachTest method.
    This method is responsible for creating the Mule message that is stored in the mTestMessage instance variable.This method is final, so subclasses cannot override it. Instead, it is recommended to override the methods discussed below that this method will delegate the different parts of test message creation to.
  • There is a method named createEmptyMuleMessage.
    This is the method that createTestMessageBeforeEachTest delegates creation of an empty Mule message to. It is the method that creates instances of the DefaultTestMuleMessage class implemented above. Subclasses are not expected to have to override this method, although it is possible.
  • There is a method named prepareTestMessage.
    This is the second delegate method that createTestMessageBeforeEachTest delegates to. In this case, the method is responsible for setting message payload and properties of the test message. Subclasses are expected to override this method.

MyTransformer Unit Test

The prerequisites for the MyTransformer unit test are now in place and the test class can be implemented like this:

Note that:

  • The MyTransformerTest class inherit from the class MuleTransformerUnitTestCase that we implemented earlier.
  • The MyTransformerTest class overrides the prepareTestMessage method.
    The prepareTestMessage method sets the payload and message properties in the message that is to be sent to the transformer under test.
    If there would have been multiple test methods in the class, the prepareTestMessage method would have been the appropriate place to set message payload and/or message properties used in all the different test methods.
    Payload and/or message properties applicable only to one single test method should be set in that particular method
  • There is a method named testMessagePropertiesSetByTransformer that is annotated with the @Test JUnit annotation.
    This is the one and only test method in this class.
  • An instance of the transformer under test is created in the testMessagePropertiesSetByTransformer method.
    It is created using new, like any POJO.
  • The test-message is sent to the transformer by invoking its transformMessage method.
    Again, no special magic – just a plain method invocation. The message to be transformed is a regular parameter.
  • Finally, the expected properties are verified in the response message from the transformer.

Run the Unit Test

If we now run the unit test, there should be a green bar indicating test success as well as some console output showing the response message from the transformer:

I would naturally not print to the console in a real unit test, I did it just to have something to show at the end of this post. 😛

Happy coding!

2 thoughts on “Unit-testing Mule transformers which access session and/or invocation scopes

  1. Hiral

    Thanks for the blog
    could you please share git project, that will really help me
    I am unable to access the gist links you posted

    Reply
    1. Ivan Krizsan Post author

      Thanks for bringing this to my attention!
      I have inserted the code into the article and updated it to run on Mule CE 3.7 and Mule CE 3.8.
      Happy coding!

      Reply

Leave a Reply

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