Mock APIKITRouter and writing MUnit test cases for different error types

  • October 30, 2020

Whenever you write MUnit test cases for any flow, coverage is one of the upmost important components. However, due to error handling, it’s difficult to get the required coverage.

You have two options to meet the coverage threshold:

  • Ignore the error handling flow
  • Write test cases for error handling

This tech article has a detailed solution on writing test cases for error handling.

Ignoring the error handling flow

To ignore a flow, you can use the ignore plugins in the POM. So, when you execute the MUnit, that flow will be ignored, and you’ll get a better coverage report.

<plugins>
  <plugin>
    <groupId>com.mulesoft.munit.tools</groupId>
    <artifactId>munit-maven-plugin</artifactId>
    <configuration>
      ...
      <coverage>
        <ignoreFlows>
             <ignoreFlow>flow-name</ignoreFlow>
        </ignoreFlows>
     </coverage>
      ...
    </configuration>
  </plugin>
</plugins>

But the MUnit Studio has a limitation with this approach: The coverage report doesn’t reflect this percentage. To get the exact coverage percentage, follow the report from the console or execute the test cases from the Command prompt.

Script for cmd execution:

mvn test or mvn clean test or mvn test -X

Writing test cases for error handling

To write a test case, you have a simple flow with one resource and one error handling block as APIKIT:BAD_REQUEST.

error handling block

The transform message of the AKIKIT:BAD_REQUEST contains a payload with a message and a variable with httpStatus — you can have any custom message in the payload based on your requirements.

payload with a message and variable with httpStatus

Now, you’ll write a test case for the main flow, which contains the error propagate block. It has a mock component as Behavior, a flow reference as an Execution step and an assert equal component in Validation.

Mock component

The Flow reference refers to the main flow:

Flow Reference

Next, configure the mock. Mock the APIKIT router and define the Error Typeid in the Error ta. Also, in the suite flow configuration, you need to define the expected error type. (These two steps are very important because, based on them, only the test case for error propagate will work).

Mock component

Mock Component

Flow configuration

Flow Configuration

For Assert That, the assertion can be based on the payload or httpStatus code. It completely depends on the user. This example uses httpStatus for validation.

httpStatus for validation

Once all the configurations are done, the test flow is set up and you can execute the test case.

Console result

= Tests run: 1 - Failed: 0 - Errors: 0 - Skipped: 0 - Time elapsed: 0.18 sec

Console Result

MUnit Studio result

Munit Studio Result

MUnit coverage report

Munit Coverage Report

NOTE: Because we haven’t written any test case for the post:\demo resource flow, only for main flow, the coverage for the demo resource flow is 0% and the main flow is 100%.

Once the test case is executed, the part that comes under the success test execution — marked with a green check — indicates successful component test cases. 

test cases

You can write similar test cases for other error types, as well.

Sample MUnit code

<?xml version="1.0" encoding="UTF-8"?>
<mule
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:munit="http://www.mulesoft.org/schema/mule/munit"
    xmlns:munit-tools="http://www.mulesoft.org/schema/mule/munit-tools"
    xmlns="http://www.mulesoft.org/schema/mule/core"
    xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
	xsi:schemaLocation="
		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
		http://www.mulesoft.org/schema/mule/munit-tools  http://www.mulesoft.org/schema/mule/munit-tools/current/mule-munit-tools.xsd">
    <munit:config name="demo-test-suite.xml" />
    <munit:test name="demo-test-suite-demo-main-BAD_REQUEST-Test" doc:id="8b6ba2d1-4696-43de-a07b-d854f4e5e2b6" description="Test" expectedErrorType="APIKIT:BAD_REQUEST">
        <munit:behavior >
            <munit-tools:mock-when doc:name="Mock when APIKIT:BAD_REQUEST" doc:id="6e68f7aa-75bf-4f15-93be-0c451375e9d9" processor="apikit:router">
                <munit-tools:with-attributes >
                    <munit-tools:with-attribute whereValue="demo-config" attributeName="config-ref" />
                </munit-tools:with-attributes>
                <munit-tools:then-return >
                    <munit-tools:error typeId="APIKIT:BAD_REQUEST" />
                </munit-tools:then-return>
            </munit-tools:mock-when>
        </munit:behavior>
        <munit:execution >
            <flow-ref doc:name="Flow-ref to demo-main" doc:id="9df72122-506f-4759-aa24-134f8341b782" name="demo-main"/>
        </munit:execution>
        <munit:validation >
            <munit-tools:assert-equals doc:name="Assert equals" doc:id="93698feb-de93-40b2-bc11-44739ad55c00" actual="#[vars.httpStatus]" expected="#[400]"/>
        </munit:validation>
    </munit:test>
    <munit:test name="demo-test-suite-demo-main-NOT_FOUND-Test" doc:id="8cfe733b-449f-4df1-b09d-06d79f63d8fb" description="Test" expectedErrorType="APIKIT:NOT_FOUND">
        <munit:behavior >
            <munit-tools:mock-when doc:name="Mock when APIKIT:NOT_FOUND" doc:id="ff561c10-4a97-456a-af92-29c144363d3d" processor="apikit:router">
                <munit-tools:with-attributes >
                    <munit-tools:with-attribute whereValue="demo-config" attributeName="config-ref" />
                </munit-tools:with-attributes>
                <munit-tools:then-return >
                    <munit-tools:error typeId="APIKIT:NOT_FOUND" />
                </munit-tools:then-return>
            </munit-tools:mock-when>
        </munit:behavior>
        <munit:execution >
            <flow-ref doc:name="Flow Reference" doc:id="5079c1a2-74ff-4591-ac6d-840b8b15e78a" name="demo-main"/>
        </munit:execution>
        <munit:validation >
            <munit-tools:assert-equals doc:name="Assert equals" doc:id="596dd171-6c28-415b-8a9d-8b9152f62cb4" actual="#[vars.httpStatus]" expected="#[404]"/>
        </munit:validation>
    </munit:test>
    <munit:test name="demo-test-suite-demo-main-METHOD_NOT_ALLOWED-Test" doc:id="635ace96-1503-40ce-8de3-13e7411726c8" description="Test" expectedErrorType="APIKIT:METHOD_NOT_ALLOWED">
        <munit:behavior >
            <munit-tools:mock-when doc:name="Mock when APIKIT:METHOD_NOT_ALLOWED" doc:id="894571a7-42b9-4caf-9be4-3c16d9cfa0f6" processor="apikit:router">
                <munit-tools:with-attributes >
                    <munit-tools:with-attribute whereValue="demo-config" attributeName="config-ref" />
                </munit-tools:with-attributes>
                <munit-tools:then-return >
                    <munit-tools:error typeId="APIKIT:METHOD_NOT_ALLOWED" />
                </munit-tools:then-return>
            </munit-tools:mock-when>
        </munit:behavior>
        <munit:execution >
            <flow-ref doc:name="Flow-ref to demo-main" doc:id="b57e4856-e333-4b45-bb01-c234f8e5e9f9" name="demo-main"/>
        </munit:execution>
        <munit:validation >
            <munit-tools:assert-equals doc:name="Assert equals" doc:id="493307c6-825b-4652-a61e-2973332a972f" actual="#[vars.httpStatus]" expected="#[405]"/>
        </munit:validation>
    </munit:test>
    <munit:test name="demo-test-suite-demo-main-NOT_ACCEPTABLE-Test" doc:id="1bec6f0d-01ed-43b2-bf39-8736cbf5e590" description="Test" expectedErrorType="APIKIT:NOT_ACCEPTABLE">
        <munit:behavior >
            <munit-tools:mock-when doc:name="Mock when APIKIT:NOT_ACCEPTABLE" doc:id="3a329baf-99df-49fb-8b18-636dc5316973" processor="apikit:router">
                <munit-tools:with-attributes >
                    <munit-tools:with-attribute whereValue="demo-config" attributeName="config-ref" />
                </munit-tools:with-attributes>
                <munit-tools:then-return >
                    <munit-tools:error typeId="APIKIT:NOT_ACCEPTABLE" />
                </munit-tools:then-return>
            </munit-tools:mock-when>
        </munit:behavior>
        <munit:execution >
            <flow-ref doc:name="Flow Reference" doc:id="a46ee38a-13b0-431d-ab94-6fafa8492ee2" name="demo-main"/>
        </munit:execution>
        <munit:validation >
            <munit-tools:assert-equals doc:name="Assert equals" doc:id="35aff4f1-30e8-4cda-b71e-736d0b279a98" actual="#[vars.httpStatus]" expected="#[406]"/>
        </munit:validation>
    </munit:test>
    <munit:test name="demo-test-suite-demo-main-UNSUPPORTED_MEDIA_TYPE-Test" doc:id="d8454189-e4e1-4375-b585-0a999a837619" description="Test" expectedErrorType="APIKIT:UNSUPPORTED_MEDIA_TYPE">
        <munit:behavior >
            <munit-tools:mock-when doc:name="Mock when APIKIT:UNSUPPORTED_MEDIA_TYPE" doc:id="f41c89d8-b712-47a4-b358-ef8cb3ba086c" processor="apikit:router">
                <munit-tools:with-attributes >
                    <munit-tools:with-attribute whereValue="demo-config" attributeName="config-ref" />
                </munit-tools:with-attributes>
                <munit-tools:then-return >
                    <munit-tools:error typeId="APIKIT:UNSUPPORTED_MEDIA_TYPE" />
                </munit-tools:then-return>
            </munit-tools:mock-when>
        </munit:behavior>
        <munit:execution >
            <flow-ref doc:name="Flow-ref to demo-main" doc:id="92675038-645a-4a98-b897-06845a04e6e3" name="demo-main"/>
        </munit:execution>
        <munit:validation >
            <munit-tools:assert-equals doc:name="Assert equals" doc:id="5065fd21-8f7f-4d1f-a6d5-042f40aefbfd" actual="#[vars.httpStatus]" expected="#[415]"/>
        </munit:validation>
    </munit:test>
    <munit:test name="demo-test-suite-demo-main-NOT_IMPLEMENTED-Test" doc:id="e2cbf56e-ee66-41cc-82be-333dd1eb292c" description="Test" expectedErrorType="APIKIT:NOT_IMPLEMENTED">
        <munit:behavior >
            <munit-tools:mock-when doc:name="Mock when APIKIT:NOT_IMPLEMENTED" doc:id="aeb6b8f2-7488-4608-b591-ee22331b85f0" processor="apikit:router">
                <munit-tools:with-attributes >
                    <munit-tools:with-attribute whereValue="demo-config" attributeName="config-ref" />
                </munit-tools:with-attributes>
                <munit-tools:then-return >
                    <munit-tools:error typeId="APIKIT:NOT_IMPLEMENTED" />
                </munit-tools:then-return>
            </munit-tools:mock-when>
        </munit:behavior>
        <munit:execution >
            <flow-ref doc:name="Flow-ref to demo-main" doc:id="bd189bb8-d517-448c-bcdf-fe043190d0a0" name="demo-main"/>
        </munit:execution>
        <munit:validation >
            <munit-tools:assert-equals doc:name="Assert equals" doc:id="302886a9-6dc6-4c96-920f-0d6f4100aa9c" actual="#[vars.httpStatus]" expected="#[501]"/>
        </munit:validation>
    </munit:test>
</mule>

Happy learning!

— By Abhishek Bathwa