A while ago I created the ESBConfigUtil test utility class (dumb name), which went some way towards making it a little easier to write tests, but was still a bit painfull. The latest addition is the AbstractTestRunner class, which I think is a bit better again. It wraps the ESBConfigUtil class, setting up the test env (ESB deployment, Registry, ESB properties ala the beloved PropertyManager), starting the ESB Controller, running the test and then shutting down the Controller and ensuring that the test env is returned to it's state from before the test run (or at least tries to ;-) ), which hopefully helps to avoid leakage between tests.
The AbstractTestRunner tries to allow you to write Integration level tests more easily. You can define a full ESB configuration and run it through the ESB Controller class, run tests (invoke endpoints etc).
As an example from the InVM transport tests, we have the following ESB configuration named "in-listener-config-01.xml":
<?xml version = "1.0" encoding = "UTF-8"?>
<jbossesb xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd">
<services>
<service category="ServiceCat" name="ServiceName"
description="Test Service">
<actions mep="RequestResponse">
<action name="action"
class="org.jboss.soa.esb.mock.MockAction" />
</actions>
</service>
</services>
</jbossesb>
Writing some test code around this, with the configuration deployed in the ESB Controller (quite near to the full running env):
public void test_async() throws Exception {
AbstractTestRunner testRunner = new AbstractTestRunner() {
public void test() throws Exception {
ServiceInvoker invoker =
new ServiceInvoker("ServiceCat", "ServiceName");
Message message = MessageFactory.getInstance().getMessage();
message.getBody().add("Hi there!");
invoker.deliverAsync(message);
sleep(50);
assertTrue(message == MockAction.message);
}
}.setServiceConfig("in-listener-config-01.xml");
testRunner.run();
}
So as you can see, the test method creates an anonymous instance of the AbstractTestRunner class. It implements the "test" method, in which the actual test code is placed. The Service config file is set on the anonymous instance through the setServiceConfig method (the String param version of this method looks up the resource using getClass().getResourceAsStream()). The ESB properties file can be set through the setEsbProperties method (supports the same mechanisms as the setServiceConfig method). Both setServiceConfig and setEsbProperties methods return the instance of the anonymous inner class (i.e. "return this;"), so you can string the config calls together e.g.:
Of course, you need to call the run() method to run the actual test code. You can do this as above, or you can just string it onto the end of the anonymous inner class:
public void test_async() throws Exception {
AbstractTestRunner testRunner = new AbstractTestRunner() {
public void test() throws Exception {
.... test code....
}
}.setEsbProperties("jbossesb-properties.xml")
.setServiceConfig("jboss-esb.xml");
testRunner.run();
}
public void test_async() throws Exception {
AbstractTestRunner testRunner = new AbstractTestRunner() {
public void test() throws Exception {
.... test code....
}
}.setServiceConfig("jboss-esb.xml").run();
}
Calling the run() method:
- Parses the Service configuration, creating the Controller instance.
- Installs the specified ESB properties (recording the currently installed properties)
- Installs and configures the Registry.
- Starts the Controller
- Calls the "test()" method to run the test code.
- Stops the Controller
- Uninstalls the Registry.
- Resets the ESB properties to their pre-test state.
Would be great if people could try it in their tests so we can evolve it and fix any issues. I hope it can make integration testing a bit easier in the 4.x codebase.