Contact Us 1-800-596-4880

Developing DevKit Connector Tests

Although DevKit doesn’t enforce writing tests, it is strongly recommended that you develop unit and functional tests for your connector as part of the development process. Connectors should not be considered production-ready without a test suite.

While testing strategy may vary extensively based on your specific needs, this document introduces the basics of what Mule and DevKit make available to support testing efforts.

Assumptions

This document assumes that you are familiar with a Java IDE (Eclipse or IntelliJ) and have familiarity with the Maven build manager for Java. It also assumes that you are at the point in your development process to prepare a test suite for your new connectors.

Areas to Test

What follows is a quick breakdown of tests you should incorporate into your test suite:

  1. Input data validation: Since your extension possibly takes in user parameters or parameters from another application, run some consistency checks on the inputs it receives. Some of the parameters taken by the cloud service may be optional, while others must adhere to certain rules. Implement unit tests that assign valid or invalid inputs to each of your connector’s methods, and check that the input validation responds accordingly.

  2. API Interaction: Because a connector typically communicates over the Internet with a remote service, your connector should handle connection or communication errors, typically by either retrying or by throwing a clear exception. Regardless of the type of error handling strategy you choose, make sure you test the error handling. You may need to mock up a testing Web service. Point the connector to your test endpoint instead of a production target so that you can more easily reproduce error conditions like timeouts or connection loss.

  3. Mule ESB Integration: When you create a new connector, make sure your test suite covers all operations. It should pass in and receive all reasonable inputs and outputs to each operation. Pay special attention to covering complex data types passed into and received from operations in XML, since these can be tricky. Test the use of default and optional parameter values in the XML to make sure they behave as expected. As a rule, test every operation and parameter at least once. Finally, make sure to test the cases where you expect the connector to raise exceptions.

  4. Studio Integration: Your connector’s appearance and usability in Studio should also be tested. Include the behavior and prompts in the properties dialog, tooltips generated from your Javadoc comments, etc. The only way to test this is to manually use the connector in Studio.

Generated DevKit Test Case Skeleton

When Maven creates a new project based on the DevKit archetype, the generated project includes a test case skeleton. This test class has some helper methods and comments that give you an idea of how to get started with writing unit tests using flows in Mule configuration. Find this file, named <yourConnectorName>test.java, in the folder src/test/java.

Note that the Java class inherits from FunctionalTestCase, the base class for all functional tests within Mule ESB.

Sample test.java file
/**
* This file was automatically generated by the Mule Development Kit
*/

package com.mulesoft.hello;
import org.mule.api.MuleEvent;
import org.mule.construct.Flow;
import org.mule.tck.FunctionalTestCase;
import org.mule.tck.AbstractMuleTestCase;
import org.junit.Test;

public class helloConnectorTest extends FunctionalTestCase
{
    @Override protected String getConfigResources()
    {
        return "mule-config.xml";
    }

    @Test public void testFlow() throws Exception
    {
        runFlowAndExpect("testFlow", "Another string");
    }

    /**
    * Run the flow specified by name and assert equality on the expected output
    *
    * @param flowName The name of the flow to run
    * @param expect The expected output
    */

    protected <T> void runFlowAndExpect(String flowName, T expect)
    throws Exception
    {
        Flow flow = lookupFlowConstruct(flowName);
        MuleEvent event = AbstractMuleTestCase.getTestEvent(null);
        MuleEvent responseEvent = flow.process(event);
        assertEquals(expect, responseEvent.getMessage().getPayload());
    }

    /**
    * Run the flow specified by name using the specified payload and assert
    * equality on the expected output
    *
    * @param flowName The name of the flow to run
    * @param expect The expected output
    * @param payload The payload of the input event
    */

    protected <T, U> void runFlowWithPayloadAndExpect(String flowName, T expect, U payload)
    throws Exception
    {
        Flow flow = lookupFlowConstruct(flowName);
        MuleEvent event = AbstractMuleTestCase.getTestEvent(payload);
        MuleEvent responseEvent = flow.process(event);
        assertEquals(expect, responseEvent.getMessage().getPayload());
    }

    /**
    * Retrieve a flow by name from the registry
    *
    * @param name Name of the flow to retrieve
    */
    protected Flow lookupFlowConstruct(String name)
    {
        return (Flow) AbstractMuleTestCase.muleContext.getRegistry().lookupFlowConstruct(name);
    }
}

Note that the Java code getConfigResources() references an XML file. The DevKit test framework looks for the named file in the src/test/resources folder. The default XML file found there is shown below:

<mule xmlns="http://www.mulesoft.org/schema/mule/core"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:spring="http://www.springframework.org/schema/beans"
   xmlns:hello="http://www.mulesoft.org/schema/mule/hello"
   xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd http://www.mulesoft.org/schema/mule/hello http://www.mulesoft.org/schema/mule/hello/1.0-SNAPSHOT/mule-hello.xsd">

  <hello:config myProperty="Some string" username="xxx" password="yyy"/>

  <flow name="testFlow">
    <hello:my-processor content="Another string"/>
  </flow>
</mule>

Generated Test Class: Helper Methods

The test class defines a number of useful helper methods to use when building individual tests

runFlowAndExpect

This method takes in two parameters:

Name Description

flowName

Mule flow to run

expect

Expected output of the test

In the default test, the XML file loads myProperty with the value Another string , which matches the expect parameter as set by the testFlow method and passes the test.

Let’s examine the method more deeply.

First, the method lookupFlowConstruct (declared below) looks for the flow you set in the parameters within the project XML configuration:

Flow flow = lookupFlowConstruct(flowName);

Then, two lines generate a test event and initiate the flow:

MuleEvent event = getTestEvent(null);
MuleEvent responseEvent = flow.process(event);

The last line compares the output of the test with the expected output that you set as a parameter of the method:

assertEquals(expect, responseEvent.getMessage().getPayload());

runFlowWithPayloadAndExpect

This method is very similar to the runFlowAndExpect method discussed above, but adds a third parameter to the test:

Name Description

flowName

Mule flow to run

expect

Expected output of the test

payload

The payload of the input event

What follows is a line-by-line examination of the method.

The first line uses the method lookupFlowConstruct (that in turn uses Mule’s Registry) to look for the flow you set as a method parameter inside the project XML configuration:

Flow flow = lookupFlowConstruct(flowName);

Then, the next two lines generate a test event using the specified payload and initiate the flow:

MuleEvent event = getTestEvent(payload);
MuleEvent responseEvent = flow.process(event);

The last line compares the output of the test with the expected output that you set as a parameter of the method.

assertEquals(expect, responseEvent.getMessage().getPayload());

assertEquals() will throw an exception if the assertion fails.

getConfigResources()

This method simply identifies the XML file from which to retrieve tests. It looks for the file in src/test/resources.

lookupFlowConstruct

This method retrieves a specified flow. It takes only one argument: name, which refers to a flow name. It is called by both runFlowAndExpect and runFlowWithPayloadAndExpect.

Adding a Test

To build a test, add a method to the generated test class, and annotate it with @Test. The @Test annotation indicates that Mule will run this method automatically when the class is instantiated.

In the default skeleton, there is already one @Test method in the file. It uses the helper method r`unFlowAndExpect` to invoke the testFlow from src/test/resources/mule-config.xml and check the result:

@Test public void testFlow() throws Exception
    {
        runFlowAndExpect("testFlow", "Another string");
    }

Feel free to modify this test or add more test methods as you need to, using the helper methods where appropriate.

For a test to pass, it should run to completion without throwing an exception. To fail a test, throw an exception in the body of the @Test method.

Next Steps

If you are developing individual unit tests while adding operations to your connector, you should go back to the development process. Build your connector project with Maven; if any of your tests fail, then your Maven build process will fail.

If you have a completed your test suite, then you can move on to completing documentation and samples for your connector.