Adding Automated tests is a critical part of productionalizing Mulesoft Integrations. Why do we need automated tests? Mostly to make sure that updates and slight modifications that are done to code over its lifecycle don’t break functionality that’s already written. In the world of micro-services, it’s critical to be able to add functionality without having to do deep integration tests every time you need a new service.

Some core tenants of good Integration Tests:

  • They test outputs (service calls) for a given set of inputs
  • They test different scenarios of input combinations
  • They test error conditions
  • They can be performed without requiring a database or another server to be set up “just so”.
  • They mock outbound calls to control conditions and not make changes

Mocking HTTP

Mocking an HTTP requester endpoint is easy and very common in Munit. In the following snippet, I’m mocking a request with the path /orders, and returning a status code with a JSON response. Mocking is the first step to creating a test environment.

<munit-tools:mock-when doc:name="Mock when" processor="http:request">
<munit-tools:with-attributes >
<munit-tools:with-attribute attributeName="path"
whereValue="/orders" />
</munit-tools:with-attributes>
<munit-tools:then-return >
<munit-tools:payload value="#[MunitTools::getResourceAsString('HTTPResponse.json')]" />
<munit-tools:attributes value="#[{'statusCode':200}]" />
</munit-tools:then-return>
</munit-tools:mock-when>

Creating an Munit SPY on the HTTP endpoint is the next step. Spying the endpoint allows the test to extract the data sent to the HTTP endpoint and test it for correctness. In the next snippet the data sent to the endpoint is checked for two things. First that it’s not null, and second that it has the correct “order number”. Field by field data checking is the preferred way.

<munit-tools:spy doc:name="Mock when" processor="http:request">
<munit-tools:with-attributes >
<munit-tools:with-attribute attributeName="path" whereValue="/orders" />
</munit-tools:with-attributes>
<munit-tools:before-call>
<set-variable value="#[output application/json --- payload]" variableName="origPayload" />
<logger message="Inside Narvar HTTP Call: #[payload]" level="INFO" doc:name="Logger" />
<munit-tools:assert-that expression="#[output application/java --- write(payload, 'application/json') as String]" is="#[MunitTools::notNullValue()]" />
<munit-tools:assert-that expression="#[output application/java --- vars.origPayload.order_info.order_number]" is="#[MunitTools::equalTo('99000055799')]" message="OrderNumber is not correct" />
</munit-tools:before-call>
</munit-tools:spy>

Mocking an External Database

Nearly all of my Mulesoft projects has a Database attached to it of some kind, so any good MUnit test will need to mock that server. Mulesoft has a bunch of directions on how to do this here: https://docs.mulesoft.com/munit/2.0/munit-database-server

I’m not going to replicate directions that are contained in the above link, since it will be better at it than I, but I will make some suggestions:

  1. Go into your Database GUI, like MySQL Workbench and export a few lines of your database tables into a CSV file, or heck, export them all, but what really matters most is your headings on the table.
  2. Make sure your Database Name in the mock, “Database”, matches your Schema name of the DB you’re using.
  3. Make sure the file name matches the table name you are using.
  4. It seems the directions on requiring the test to “Start the Server” in the before test place are incorrect. The server is already started.
 <dbserver:config name="MUnit_DB_Server_Config" doc:name="MUnit DB Server Config" >
<dbserver:connection csv="my-database-table.csv" database="MulesoftESB" connectionStringParameters="MODE=MySQL" />
</dbserver:config>

Once the database is instantiated you can do all the regular database calls you would, and then also verify in Munit that the database has been changed by the application code

Mocking and Spying SQS

In the next bit of code I’m both Mocking SQS, and then SPYing the payload send to SQS for correctness.

<munit:behavior>
<munit-tools:mock-when doc:name="Mock when" processor="sqs:send-message">
<munit-tools:with-attributes>
<munit-tools:with-attribute attributeName="queueUrl" whereValue="${sqs.orderscreatequeue}" />
</munit-tools:with-attributes>
<munit-tools:then-return>
<munit-tools:payload value="#[output application/json --- payload]" mediaType="application/json" />
</munit-tools:then-return>
</munit-tools:mock-when>
<munit-tools:spy doc:name="SQS-Spy" processor="sqs:send-message">
<munit-tools:with-attributes>
<munit-tools:with-attribute attributeName="queueUrl" whereValue="${sqs.orderscreatequeue}" />
</munit-tools:with-attributes>
<munit-tools:before-call>
<set-variable value="#[output application/json   --- read(payload.body)]" doc:name="Set Variable" variableName="origPayload" />
<munit-tools:assert-that expression="#[output application/java --- write(payload, 'application/json') as String]"
is="#[MunitTools::notNullValue()]" />
<munit-tools:assert-that expression="#[output application/java --- vars.origPayload.items[0].description]" is="#[MunitTools::equalTo('Levi\'s (R) 550 (TM) Relaxed Jeans')]" message="Ordered Item Description is not correct" />
</munit-tools:before-call>
</munit-tools:spy>
</munit:behavior>

SQS has some of it’s own idiosyncrasies regarding the data model. That’s a different blog post entirely.

Good luck Muniting!!