Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Intro to MUnit and Mule Runtime

DZone's Guide to

Intro to MUnit and Mule Runtime

In what kind of use case would you want to write MUnit test cases, and how can you write and run those test cases in Anypoint Studio?

· Integration Zone
Free Resource

Modernize your application architectures with microservices and APIs with best practices from this free virtual summit series. Brought to you in partnership with CA Technologies.

Today, we will be talking about testing in Mule ESB applications. In any kind of technological development, testing plays a major part. With testing, you make sure that the code you have written can withstand the rough environment of production. Testing can be of various types depending on your specific needs, i.e., the type of product or application you are involved in developing.

As a Mule developer, there are two main types of testing you should be interested in.

  1. Unit testing.

  2. Integration testing.

Unit Testing

As the name suggests, unit testing is a process by which you test the smallest unit of your source code. What you call the smallest unit can vary according to the programming principals you are working on, but it always concentrated on validating the correctness of an individual unit of code.

In a Mule application, we consider the smallest testable part to be a Mule flow (sub-flow), so this is our unit of code.

A good unit test should be independent of others. Why? Because if it depends on another component and fails during testing, it becomes difficult to judge which component has failed. To avoid mistakes of failure of the wrong component as the failure of the unit under test, always make your unit test is independent.

To isolate unit test case in Mule we can use mock messages, we will talk more about it later.

Integration Testing

An application is built by the collaboration of smaller units, in a unit test, you test the smaller units. In integration testing, you test how these units of code respond when collaborating with each other. The intention is to validate how different units of code and modules work together.

Coding for Testing

When coding for testing, it's helpful to consider the following guidelines.

Write Short Flows

If your code is very long, then it is very hard to unit test. Try to avoid long flows. The rule of thumb is that if you have to scroll your screen to see the whole flow, it is too long. Try to divide it into sub-flows.

Modularize

Just like you shouldn't write all of your code in a single class file, you shouldn't put all your flows in single file. The best way is to group the code is based on common goals or functional areas.

Environmentalism

Parameterize your code to work in different environments (i.e., dev, test, prod, etc.) using placeholders (for example, the settings of DB or outbound HTTP endpoints).

Readability and Maintainability

Write your test like you write your code: make it readable and maintainable. Give proper names to your tests.

Error Message

Always give proper error messages to you your test cases a wrongly written or ambiguous is worse than doing no testing.

MUnit

MUnit is a Mule testing framework that lets you easily automate testing Mule applications, using both unit and integration tests. MUnit also provides a set of tools, such as a message processor mocking framework that lets you test units of code in actual isolation.

Demo of MUnit

In this part of the article, I will be explaining the use case for which we will be writing MUnit test cases. I will show how to write and run those test cases in Anypoint Studio.

Main Flow

In this use case, the main flow is using HTTP inbound endpoint and extracts the information from the HTTP-params sent to the inbound. Then, it calls another flow and sends the information as a payload. Our main flow has a choice, which depends upon the variable set by the decision flow and sub-flow.

Image title

Decision Flow

Image title

The decision flow uses the payload sent by the main flow and takes the decision of calling the two sub-flows. These sub-flows will simply set a variable with some value.

Here's the complete XML:

<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:metadata="http://www.mulesoft.org/schema/mule/metadata" xmlns:context="http://www.springframework.org/schema/context"
xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking"
xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-current.xsd">
<http:listener-config name="HTTP_Listener_Configuration"
host="0.0.0.0" port="${http.port}" doc:name="HTTP Listener Configuration" />
<context:property-placeholder

location="application-setting.properties,application-setting-2.properties" />
<flow name="main-flow">
        <http:listener config-ref="HTTP_Listener_Configuration" path="/mutest" doc:name="HTTP">
            <http:response-builder statusCode="200" reasonPhrase="OKHai" disablePropertiesAsHeaders="true">
                <http:header headerName="sessionid" value="24385"/>
                <http:header headerName="onemoreprop" value="ggjghj"/>
            </http:response-builder>
            <http:error-response-builder statusCode="500" reasonPhrase="FatGaya"/>
        </http:listener>
<set-payload
value="#[message.inboundProperties.'http.query.params'.['decisionKey']]"
doc:name="Set Payload" />
<flow-ref name="decisionFlow" doc:name="decisionFlow" />
<choice doc:name="Choice">
<when expression="#[flowVars.decisionVariable.equals('decision1')]">
<set-payload value="#['Decision 1 was taken']" doc:name="Set Response Payload" />
</when>
<otherwise>
<set-payload value="#['Decision 2 was taken']" doc:name="Set Response Payload" />
</otherwise>
</choice>
</flow>
<flow name="decisionFlow">
<choice doc:name="Choice">
<when expression="#['value1'.equals(payload)]">
<flow-ref name="decision1SubFlow" doc:name="decision1SubFlow" />
</when>
<otherwise>
<flow-ref name="decision2SubFlow" doc:name="decision2SubFlow" />
</otherwise>
</choice>
</flow>
<sub-flow name="decision1SubFlow">
<set-variable variableName="decisionVariable" value="#['decision1']"
doc:name="decisionVariable" />
</sub-flow>
<sub-flow name="decision2SubFlow">
<set-variable variableName="decisionVariable" value="#['decision2']"
doc:name="decisionVariable" />
</sub-flow>
</mule>

Testing the Flow Using Postman

We will call our flow using Postman and send decisionKey as query param with two different values.

Image title

Image title

As we can see, our use case runs properly. In the second part of this series, I will be showing you how to write MUnit test cases to test our various flows.

The Integration Zone is proudly sponsored by CA Technologies. Learn from expert microservices and API presentations at the Modernizing Application Architectures Virtual Summit Series.

Topics:
mule ,munit ,mulesoft ,anypoint platform ,integration

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}