In part 2 of this mini-series I showed a flow that retrieves an RSS feed periodically, splits it and sends each RSS entry via email. In this part I’d like to show how to split up the flow a bit in order to enable unit testing.
To refresh your memory here’s what the flow currently looks like:
Testing this flow is hard if not impossible for a number of reasons:
- The URL of the feed is hard-coded. This is bad because a test should not rely on an external resource. If that resource is not available the test will produce a failure that is not caused by the functionality in the code. Also, the unit test has no chance of knowing the contents of the feed. So there is no way to assert e.g. if the subject message property is set up correctly as it is extracted from the feed.
- The flow always sends the individual feed entries to an SMTP endpoint. This makes the test a lot more complicated: it would need to connect to your email server and check if new messages arrived. Also, as noted above, the test does not know the contents of the feed before it executes. So even if you implemented checking your email account you would still not be able to say with confidence if the flow works correctly.
Let’s refactor a bit to make the flow testable. The first step is to decouple feed splitting from the HTTP inbound endpoint so that we can send arbitrary feed data in. This is easy, we just need to move the polling HTTP part to its own flow
The main functionality that we want to test is in a separate flow now. The messages that come in from HTTP polling are just forwarded to the feedSplitter flow.
But how do we send data to this flow from a unit test? We take advantage of the fact that flows are stored in Mule’s internal registry. We just look it up from the unit test and make it process a test event:
Note that the muleContext variable and the getTestEvent() methods are goodies you inherit from FunctionalTestCase.
Now that we have decoupled the flow from receiving the messages we only need to get rid of the dependency to the SMTP transport. We could use the same approach as shown above but for the sake of this example I’d like to use a different solution: In the flow we don’t specify a transport specific endpoint but we rather use a reference to a global endpoint named sendMail:
Now we have isolated the feed splitting functionality from the inbound and outbound channels. For better reuse we simply extract the flow into its own config file called feed-split-config.xml. Now we can include that config in the functional test’s config like this:
In the unit test we can now use a MuleClient to retrieve the individual feed messages from the feedSplitter flow:
That’s it! With minimal changes to the configuration we made the feed splitting flow testable. I have added the project as version 3 to the github repository so you can download and run the unit test locally.