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

MUnit and Mule Runtime: Part II

DZone's Guide to

MUnit and Mule Runtime: Part II

MUnit test cases — both unit and functional — can pretty easily be used to test various flows, whether they're main flows, decision flows, or sub-flows.

· Integration Zone
Free Resource

Share, secure, distribute, control, and monetize your APIs with the platform built with performance, time-to-value, and growth in mind. Free 90-day trial of 3Scale by Red Hat

This blog is the continuation of my previous blog about MUnit, so if you have not read it yet, I would highly recommend that you go through it before continuing. Alternatively, you can watch the video tutorial on YouTube.

Let’s get going. If you remember last time, we created a Mule project with four flows: a main flow, a decision flow, and two sub-flows. 

So, we will be writing a unit test case for the decision flow and a functional test case for the decision flow and sub-flows. With this, we will be able to cover both unit test and function test cases.

Unit Test Case

As I explained in the last blog, while doing unit testing, we try to isolate the part of code that is under test as much as possible. If it depends on some other part of code, we try to mock it with replacement dummy functions. It's the same case with Mule flows. When we write unit test cases for a flow and the flow under test is calling other flows, we try to mock the flows and test the single flow in its entirety.

When doing unit tests, you isolate your flow from third-party systems and other flows and trust they work as expected. In turn, you must test each third-party system or flow with its own specific test.

If the flow takes different actions based on different values of the payload or on the contents of a variable, we should design more that one test for that flow.

One important point to remember is in MUnit you don’t mock or verify flow-ref, we mock or verify the flow andsub-flow.

MUnit Initialization

Any MUnit test case starts with the initialization of MUnit and importing of the XML config file where you have written your flows that you want to test.

<munit:config name="munit"doc:name="MUnit configuration"/>
  <spring:beans>    
  <spring:importresource="classpath:munit-demo.xml"/>
</spring:beans>

Unit Test Case 1 (sub-flow-test-suite.xml)

Since our smallest part of the code are the sub-flows, we will write the unit tests for them first.

 Image title

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

<mule xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:munit="http://www.mulesoft.org/schema/mule/munit" xmlns:spring="http://www.springframework.org/schema/beans"
xmlns:core="http://www.mulesoft.org/schema/mule/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/munit http://www.mulesoft.org/schema/mule/munit/current/mule-munit.xsd
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">

<munit:config name="munit" doc:name="MUnit configuration" />

<spring:beans>
<spring:import resource="classpath:munit-demo.xml" />
</spring:beans>



<munit:test name="sub-flow-test-suite-decision1SubFlowTest"
description="Test">
<flow-ref name="decision1SubFlow" doc:name="Flow-ref to decision1SubFlow" />
<munit:assert-on-equals expectedValue="#['decision2']"
actualValue="#[flowVars.decisionVariable]" doc:name="Assert Equals"
message="Sorry did not got expected Value i.e. decision1 insted we got #[flowVars.decisionVariable]" />
</munit:test>
</mule>

Let’s understand what’s going on here. Since the task of these sub-flows is just to set the flow variable named decisionVariable, we are going to simply make a flow reference to these two flows and use the munit:assert-on-equals function to check the value of flow variable to be equal to the expected value.

Unit Test Case 2 (decision-flow-test-suite.xml)

In our flows, the decision flow is the place where we decide (based on the payload sent by the main flow) which sub-flow to go, using the choice router of Mule. Those sub-flows set the decision variable into flow vars. We will be writing two test cases for decision flow (actually four) where first we will test that the correct sub-flow is being invoked when we send the proper payload. In a separate test case, we will test if the correct flow variable is being set by sub-flows. There are four possibilities (for example, invocation of two sub-flows and return of two different values of flow variables) — that is the reason I said four test cases.

Testing Invocation of Sub-Flows

Image title

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

<mule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mock="http://www.mulesoft.org/schema/mule/mock" xmlns:munit="http://www.mulesoft.org/schema/mule/munit"
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"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/mock http://www.mulesoft.org/schema/mule/mock/current/mule-mock.xsd
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/munit http://www.mulesoft.org/schema/mule/munit/current/mule-munit.xsd">
<munit:config name="munit" doc:name="MUnit configuration" />
<spring:beans>
<spring:import resource="classpath:munit-demo.xml" />
</spring:beans>


<munit:test name="decision-flow-test-mock-call-1-suiteTest"
description="MUnit Test">
<set-payload doc:name="Set Payload" value="#['value1']" />
<flow-ref name="decisionFlow" doc:name="decisionFlow" />
<mock:verify-call doc:name="Verify Call"
messageProcessor="mule:sub-flow" times="1">
            <mock:with-attributes>
                <mock:with-attribute name="name" whereValue="#[matchContains('decision1SubFlow')]"/>
            </mock:with-attributes>
</mock:verify-call>
</munit:test>


<munit:test name="decision-flow-flow-var-1-suiteTest"
description="MUnit Test">
<set-payload doc:name="Set Payload" value="#['value1']" />
<flow-ref name="decisionFlow" doc:name="decisionFlow" />
<munit:assert-on-equals expectedValue="#['decision1']"
actualValue="#[flowVars.decisionVariable]" doc:name="Assert Equals"
message="Sorry did not got expected Value i.e. decision1 insted we got #[flowVars.decisionVariable]" />

</munit:test>

</mule>

In this test case, we are setting the payload value before calling the decisionFlow using the flow-ref. Then, by using the mock:verify-call, we verify that the correct sub-flow is being invoked.

In verify-call, an important thing to notice is that I have used matchContains, a matcher of MUnit.

When mocking or verifying a sub-flow and using the name attribute, always use the MUnit matcher matchContains.

This is not needed when verifying or mocking flows — only for sub-flows. I have not given the XML part of the send test. I'll leave it up to you to try to implement it.

Testing Flow Variable Value

<munit:test name="decision-flow-flow-var-1-suiteTest"
description="MUnit Test">
<set-payload doc:name="Set Payload" value="#['value1']" />
<flow-ref name="decisionFlow" doc:name="decisionFlow" />
<munit:assert-on-equals expectedValue="#['decision1']"
actualValue="#[flowVars.decisionVariable]" doc:name="Assert Equals"
message="Sorry did not got expected Value i.e. decision1 insted we got #[flowVars.decisionVariable]" />

</munit:test>

This test case is very similar to the test case for sub-flows. The only difference is that we are setting the payload value, and instead of calling sub-flow, we make a call to decision flow.

The Assert part of decision variable is completely the same. We could have easily merged this test case with the invocation test case, but it’s always a good idea to separate your test cases so that they have only one responsibility: testing only one function.

Again, I left the second test case implementation for you to try.

I will end here. In the next (and last) part of this blog series, we will see how to unit test our main flow. Testing the main flow is going to be tricky because we are required to mock the flow reference calls. We will also see how to write functional tests (end-to-end testing of our flow).

Explore the core elements of owning an API strategy and best practices for effective API programs. Download the API Owner's Manual, brought to you by 3Scale by Red Hat

Topics:
mule ,munit ,integration ,unit testing ,functional testing

Published at DZone with permission of Harish Kumar, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}