Red Hat Training

A Red Hat training course is available for Red Hat Fuse

13.10. Useful Tips for Creating JUnit Tests

13.10.1. Using Harmcrest to Assert

Hamcrest is a framework for writing matcher objects. It allows you to define match rules declaratively. Use Hamcrest’s assertThat construct and the standard set of matchers, both of which you can statically import:
import static org.hamcrest. MatcherAssert .assertThat;
import static org.hamcrest. Matchers .*;
Hamcrest comes with a library of useful matchers, such as:
  • Core
    • anything: Always matches, useful if you do not want to know what the object under test is
    • describedAs: Decorator for adding custom failure description
    • is: Decorator to improve readability
  • Logical
    • allOf: Matches if all matchers match, short circuits (like && in Java)
    • anyOf: Matches if any matchers match, short circuits (like || in Java)
    • not: Matches if the wrapped matcher does not match and vice versa
  • Object
    • equalTo: Test object equality using Object.equals
    • hasToString: Test Object.toString
    • instanceOf, isCompatibleType: Test type
    • notNullValue, nullValue: Test for null
    • sameInstance: Test object identity
  • Beans
    • hasProperty: Test JavaBeans properties
  • Collections
    • array: Test an array’s elements against an array of matchers
    • hasEntry, hasKey, hasValue: Test a map contains an entry, key or value
    • hasItem, hasItems: Test a collection contains elements
    • hasItemInArray: Test an array contains an element
  • Number
    • closeTo: Test floating point values are close to a given value
    • greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo: Test ordering
  • Text
    • equalToIgnoringCase: Test string equality ignoring case
    • equalToIgnoringWhiteSpace: Test string equality ignoring differences in runs of whitespace
    • containsString, endsWith, startsWith: Test string matching

13.10.2. Invoking a Component Service

In order to invoke a component service, you must inject an invoker for certain ServiceOperation. When injecting a service operation, specify it in [service_name].[operation_name] notation.
import org.switchyard.test.Invoker;
...

@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(mixins = CDIMixIn.class)
public class ExampleServiceTest {

    @ServiceOperation("ExampleService.submitOperation")
    private Invoker submitOperation;

    @Test
    public void testOK() throws Exception {
        ParamIn testParam = new ParamIn()
            .set...(...);

        ParamOut result = submitOperation
            .sendInOut(testParam)
            .getContent(ParamOut.class);

        Assert....
    }

    @Test
    public void testForFault() throws Exception {
        ParamIn testParam = new ParamIn()
            .set...(...);

        try{
            // This method invocation should throw a fault
            ParamOut result = submitOperation
                .sendInOut(testParam)
                .getContent(ParamOut.class);

            Assert.fail
        } catch (InvocationFaultException ifex){
            Assert.... // Assert for correct type of exception
        }
    }
An invocation to a service operation can throw a InvocationFaultException whenever the method throws a fault. So catching this exception is similar to validating for the fault being thrown.
You can:
  • Check against original exception by checking the type of the InvocationFaultException:
     ifex.isType(MyOriginalException.class)
    
  • Use the JUnit functionality of setting the expected exception in the test:
     @Test(expected=org.switchyard.test.InvocationFaultException.class)
    

13.10.3. SwitchYardTestKit Utility Methods

TestKit provides the following set of utility methods to ease validations and some common operations that are performed on test classes:
  • Access to underlying
    • getTestInstance
    • getActivators
    • getDeployment
    • getServiceDomain
    • createQName
  • Service manipulation
    • registerInOutService
    • registerInOnlyService
    • removeService
    • replaceService
  • Invocation
    • newInvoker
  • Transformations
    • addTransformer
    • newTransformer
    • registerTransformer
  • MixIns
    • getMixIns
    • getMixIn
  • Dependencies
    • getRequiredDependencies
    • getOptionalDependencies
  • Resources
    • getResourceAsStream
    • readResourceBytes
    • readResourceString: Reads a resource (file) form the classpath
    • readResourceDocument
  • Configuration
    • loadSwitchYardModel
    • loadConfigModel
  • XML Comparison
    • compareXMLToResource: Compares a XML in string format with a XML file in the classpath.
    • compareXMLToString
  • Tracing
    • traceMessages: enables message tracing for the application under test.

13.10.4. Testing Transformations in Component Service

While testing a component invocation, you can test for the appropriate transformation with additional methods on the invocation. You can do this for the input transformation, as well as for the output transformation as shown below:
...

    @ServiceOperation("ExampleService.submitOperation")
    private Invoker serviceOperationInvocation;

    @Test
    public void testForInputTransformation() throws Exception {
        ParamOut result =  serviceOperationInvocation
                           .inputType(QName.valueOf("{urn:com.examaple:service:1.0"}submitOperation))
                           .sendInOut(....)
                           .getContent(ParamOut.class);
        Assert....  // Assert that result is OK, so transformation was OK
    }

    @Test
    public void testForOutputXMLTransformation() throws Exception {
        ParamIn testParam = new ParamIn()
            .set...(...);

        ParamOut result =  serviceOperationInvocation
                           .expectedOutputType(QName.valueOf("{urn:com.examaple:service:1.0"}submitOperationResponse))
                           .sendInOut(testParam)
                           .getContent(Element.class); // Expect Element as transformation is for XML

        XMLAssert....  // Assert that result is what is expected
    }
You can use XMLUnit and XMLAssert from org.custommonkey.xmlunit to ease validations.

13.10.5. Mocking a Service, Component, or Reference

Mocking a component may be useful, so it is never invoked for the sake of a test. For this, SwitchYardTestKit provides with the ability of adding, replacing, or removing services.
 // replace existing implementation for testing purposes
    testKit.removeService("MyService");s
    final MockHandler myService = testKit.registerInOnlyService("MyService");

    .... // Invoke the service under test

    // Assert what has arrived ath the mocked service
    final LinkedBlockingQueue<Exchange> recievedMessages = myService.getMessages();
    assertThat(recievedMessages, is(notNullValue()));

    final Exchange recievedExchange = recievedMessages.iterator().next();
    assertThat(recievedExchange.getMessage().getContent(String.class), is(equalTo(...)));
  • If you want to assert what has arrived or produced in the MockHandler, you can use the following options:
    • getMessages(): This provides with the list of received messages.
    • getFaults(): This provides with the list of prodced faults.
  • If the service is InOut, you may need to mock a response. You can use the following options:
    • forwardInToOut()
    • forwardInToFault()
    • replyWithOut(Object)
    • replyWithFault(Object)
      For example:
      final MockHandler mockHandler = testKit.registerInOutService("MyService");
          mockHandler.forwardInToOut();
  • If you want to instruct the MockHandler to wait for certain message, you can use the following options:
    • waitForOkMessage()
    • waitForFaultMessage()
      The MockHandler waits for 5 seconds by default, unless instructed to wait for a different period with setWaitTimeout(milis).

13.10.6. Mocking a Service For More Than One Method Invocation

In some cases, the service you are mocking may be called
  • Twice in the context of a single unit test, or
  • Multiple times for the same method, or
  • Multiple times for different methods
In this case, you can register an ExchangeHandler with the mock, while registering and replacing the original service. The ExchangeHandler gets the message, and contains the logic that you need to put to deal with this scenario, as shown below:
 testKit.replaceService(qname, new ExchangeHandler() {

        @Override
        public void handleMessage(Exchange arg0) throws HandlerException {
            // Here logic to handle with messages
        }

        @Override
        public void handleFault(Exchange arg0) throws HandlerException {
            // Here logic to handle with faults
        }
    });
You can reuse this ExchangeHandler by making it a named class (not anonymous).

13.10.6.1. Multiple Invocations of a Single Method

In the case of multiple invocation of the same method, the ExchangeHandler keeps track of the invocation number, in case it has to answer with different messages:
testKit.replaceService(qname, new ExchangeHandler() {
        int call=1;

        @Override
        public void handleMessage(Exchange exchange) throws HandlerException {
            if (call++ == 1){ // First call
                // Do whatever wants to be done as result of this operation call, and return the expected output
                Result result = ...; / Result is return type for operation store
                exchange.send(exchange.createMessage().setContent(result));
            }else if (call++ == 2){ // Second call
                // Do whatever wants to be done as result of this operation call, and return the expected output
                Result result = ...; / Result is return type for operation store
                exchange.send(exchange.createMessage().setContent(result));
            }else{
                throw new HandlerException("This mock should not be called more than 2 times");
            }
        }

        @Override
        public void handleFault(Exchange exchange) throws HandlerException {
            // Here logic to handle with faults
        }
    });

13.10.6.2. Multiple Invocations of Different Methods

In the case of multiple invocation of different methods, the ExchangeHandler checks for operation name, to know which method is being invoked:
testKit.replaceService(qname, new ExchangeHandler() {

        @Override
        public void handleMessage(Exchange exchange) throws HandlerException {
            if (exchange.getContract().getProviderOperation().getName().equals("store")){
                // Do whatever wants to be done as result of this operation call, and return the expected output
                Result result = ...; / Result is return type for operation store
                exchange.send(exchange.createMessage().setContent(result));
            }else if (exchange.getContract().getProviderOperation().getName().equals("getId")){
                // Do whatever wants to be done as result of this operation call, and return the expected output
                exchange.send(exchange.createMessage().setContent(1)); // This operation returns a Int
            }else{
                throw new HandlerException("No operation with that name should be executed");
            }
        }

        @Override
        public void handleFault(Exchange exchange) throws HandlerException {
            // Here logic to handle with faults
        }
    });

13.10.7. Setting Properties For a Test

You can use the PropertyMixIn property to set test properties in configurations, as shown below:
   private PropertyMixIn pmi;

   ...
   pmi.set("test.property.name", "test");
   pmi.set("test.property.name", Integer.valueOf(100));
   ...
   pmi.get("test.property.name");
   ...

13.10.8. Testing a Deployed Service with HTTPMixin

Use HTTPMixin to test a deployed service, as shown below:
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(
        scanners = TransformSwitchYardScanner.class,
        mixins = {CDIMixIn.class, HTTPMixIn.class})
public class WebServiceTest {

    private HTTPMixIn httpMixIn;

    @Test
    public void invokeWebService() throws Exception {
        // Use the HttpMixIn to invoke the SOAP binding endpoint with a SOAP input (from the test classpath)
        // and compare the SOAP response to a SOAP response resource (from the test classpath)...
        httpMixIn.setContentType("application/soap+xml");
        httpMixIn.postResourceAndTestXML("http://localhost:18001/service-context/ServiceName", "/xml/soap-request.xml", "/xml/soap-response.xml");
    }
}
You can also use HTTPMixin from a main class, as shown below:
    /**
     * Only execution point for this application.
     * @param ignored not used.
     * @throws Exception if something goes wrong.
     */
    public static void main(final String[] ignored) throws Exception {

        HTTPMixIn soapMixIn = new HTTPMixIn();
        soapMixIn.initialize();

        try {
            String result = soapMixIn.postFile(URL, XML);
            System.out.println("SOAP Reply:\n" + result);
        } finally {
            soapMixIn.uninitialize();
        }
    }

13.10.9. Creating an Embedded WebService to Test a Component

In situations where you wish to only test a single component, you can expose it dynamically as a WebService and invoke it, as shown below:
import javax.xml.ws.Endpoint;
...

@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(
        config = SwitchYardTestCaseConfig.SWITCHYARD_XML,
        scanners = {TransformSwitchYardScanner.class},
        mixins = {HTTPMixIn.class})
public class CamelSOAPProxyTest {

    private static final String WEB_SERVICE = "http://localhost:8081/MyService";

    private HTTPMixIn _http;
    private Endpoint _endpoint;

    @BeforeDeploy
    public void setProperties() {
        System.setProperty("org.switchyard.component.http.standalone.port", "8081");
    }

    @Before
    public void startWebService() throws Exception {
        _endpoint = Endpoint.publish(WEB_SERVICE, new ReverseService());
    }

    @After
    public void stopWebService() throws Exception {
        _endpoint.stop();
    }

    @Test
    public void testWebService() throws Exception {
        _http.postResourceAndTestXML(WEB_SERVICE, "/xml/soap-request.xml", "/xml/soap-response.xml");
    }
}

13.10.10. Testing a Deployed Service with HornetQMixIn

When you need to test an application that has a JMS binding, you may want to test with the binding itself. In such cases, you can use HornetQMixIn. HornetQMixIn gets its configuration from the following two files, which must be present on the classpath for the test:
  • hornetq-configuration.xml: This file contains the configuration for the HornetQ server.
    <configuration xmlns="urn:hornetq">
    
            <paging-directory>target/data/paging</paging-directory>
            <bindings-directory>target/data/bindings</bindings-directory>
            <persistence-enabled>false</persistence-enabled>
            <journal-directory>target/data/journal</journal-directory>
            <journal-min-files>10</journal-min-files>
            <large-messages-directory>target/data/large-messages</large-messages-directory>
            <security-enabled>false</security-enabled>
    
            <connectors>
                    <connector name="invm-connector">
                            <factory-class>org.hornetq.core.remoting.impl.invm.InVMConnectorFactory</factory-class>
                    </connector>
                    <connector name="netty-connector">
                     <factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class>
                     <param key="port" value="5545"/>
          </connector>
            </connectors>
    
            <acceptors>
                    <acceptor name="invm-acceptor">
                            <factory-class>org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory</factory-class>
                    </acceptor>
                    <acceptor name="netty-acceptor">
                            <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
                            <param key="port" value="5545"/>
                    </acceptor>
            </acceptors>
    
    </configuration>
    
    Important
    The camel-netty component is deprecated since JBoss Fuse 6.3 and will be replaced by the camel-netty4 component in a future release of JBoss Fuse.
  • hornetq-configuration.xml: This file contains the definition of the connection factories, queues, and topics.
    <configuration xmlns="urn:hornetq">
    
       <connection-factory name="ConnectionFactory">
          <connectors>
            <connector-ref connector-name="invm-connector"/>
          </connectors>
    
          <entries>
             <entry name="ConnectionFactory"/>
          </entries>
       </connection-factory>
    
       <queue name="TestRequestQueue">
          <entry name="TestRequestQueue"/>
       </queue>
       <queue name="TestReplyQueue">
          <entry name="TestReplyQueue"/>
       </queue>
    
    </configuration>
    
To use HornetQMixIn in a test, you need to get a reference to the MixIn and use the appropriate mixin methods, as shown below:
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(
        config = SwitchYardTestCaseConfig.SWITCHYARD_XML,
        mixins = {CDIMixIn.class, HornetQMixIn.class}
)

public class JmsBindingTest {

    private HornetQMixIn _hqMixIn;


    @Test
    public void testHelloService() throws Exception {
        Session session = _hqMixIn.getJMSSession();
        MessageProducer producer = session.createProducer(HornetQMixIn.getJMSQueue(REQUEST_NAME));
        Message message = _hqMixIn.createJMSMessage(createPayload(NAME));
        producer.send(message);

        MessageConsumer consumer = session.createConsumer(HornetQMixIn.getJMSQueue(REPLY_NAME));
        message = consumer.receive(3000);
        String reply = _hqMixIn.readStringFromJMSMessage(message);
        SwitchYardTestKit.compareXMLToString(reply, createExpectedReply(NAME));
    }

    @Before
    public void getHornetQMixIn() {
        _hqMixIn = _testKit.getMixIn(HornetQMixIn.class);
    }


You can also test from a standalone client, as shown below:
public static void main(final String[] args) throws Exception {

        HornetQMixIn hqMixIn = new HornetQMixIn(false)
                                    .setUser(USER)
                                    .setPassword(PASSWD);
        hqMixIn.initialize();

        try {
            Session session = hqMixIn.getJMSSession();
            final MessageProducer producer = session.createProducer(HornetQMixIn.getJMSQueue(REQUEST_NAME));
            producer.send(hqMixIn.createJMSMessage("<....>");
            System.out.println("Message sent. Waiting for reply ...");

            final MessageConsumer consumer = session.createConsumer(HornetQMixIn.getJMSQueue(REPLY_NAME));
            Message message = consumer.receive(3000);
            String reply = hqMixIn.readStringFromJMSMessage(message);
            System.out.println("REPLY: \n" + reply);
        } finally {
            hqMixIn.uninitialize();
        }

    }

13.10.11. Testing a Deployed Service with TransactionMixIn

You can use TransactionMixIn to test your required services with a transaction. TransactionMixIn with combination of CDIMixIn injects a UserTransaction object when required. If you need explicit access, you can use @Inject in the UserTransaction object. otherwise, it is injected in SwitchYard’s functionalities. This MixIn introduces NamingMixIn, as it is a required dependency.
@SwitchYardTestCaseConfig(
    config = SwitchYardTestCaseConfig.SWITCHYARD_XML,
    mixins = {CDIMixIn.class, TransactionMixIn.class}
)
public YourClass{
    ....
}
This binds the following objects into the JNDI tree:
  • TransactionManager: java:jboss/TransactionManager
  • UserTransaction: java:jboss/UserTransaction
  • TransactionSynchronizationRegistry: java:jboss/TransactionSynchronizationRegistry
If you need access to the provided objects, you can use the MixIn to get a reference, as shown below:
    private TransactionMixIn transaction;
    ....
    transaction.getUserTransaction();
    transaction.getTransactionManager();
    transaction.getSynchronizationRegistry();

This mixin creates transactional logs in target/tx-store and uses Arjuna Transactions Provider (com.arjuna.ats.jta).

13.10.12. Testing With a Different SwitchYard Configuration File

You can use the following annotation on the test class and create your reduced <switchyard-XXXX.xml> within the test/resources folder at the same package level as your test class:
@SwitchYardTestCaseConfig(config = "switchyard-XXXXX.xml", mixins = {.....})

13.10.13. Selectively Enabling Activators for a Test

The test framework defaults to a mode where the entire application descriptor is processed during a test run. This means all gateway bindings and service implementations are activated during each test. There are times when this may not be appropriate. So you must allow activators to be selectively enabled or disabled based on your test configuration. In the example below, SOAP bindings are excluded from all tests. This means that SOAP gateway bindings are not activated when the test framework loads the application.
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(config = "testconfigs/switchyard-01.xml" exclude="soap")
public class NoSOAPTest  {
   ...
}
The example below includes only CDI bean services as defined in the application descriptor:

@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(config = "testconfigs/switchyard-02.xml" include="bean")
public class BeanServicesOnlyTest  {
...
}
You may need to add some procedures before you perform the test. The JUnit @Before operation is invoked immediately after the application is deployed. However, you can not use it if you expect something to happen before deployment.

13.10.14. Preparing Procedure for Test

JUnit @Before operation is invoked right after the application is deployed. So, you can not use @Before operation if you expect something before deployment. Use @BeforeDeploy annotation when you need to add some procedures before a test is performed.

13.10.15. Testing a Camel Binding

If you are exposing services with a camel binding, you can test it by getting the CamelContext and then creating a ProducerTemplate as shown below:
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(
        config = SwitchYardTestCaseConfig.SWITCHYARD_XML,
        mixins = { CDIMixIn.class })
public class ExampleTest {

    private SwitchYardTestKit testKit;

    @Test
    public void testIntake() throws Exception {
        ServiceDomain domain = testKit.getServiceDomain();
        CamelContext ctx = (CamelContext)domain.getProperty("CamelContextProperty");
        ProducerTemplate producer = ctx.createProducerTemplate();
        producer.sendBody("direct://HelloService", "Message content");
    }
}
You can test a service like the one defined below that has a camel binding:
<sca:service name="Hello/HelloService" promote="Hello/HelloService">
   <sca:interface.java interface="org.jboss.example.ExampleService"/>
   <camel_1:binding.uri name="camel1" configURI="direct://HelloService"/>
</sca:service>