An interesting Mule app to create complex MUnits
Tags: mulesoft, munit, testing, backend
Published: 2024-04-16 17:03:54

This is a Mule application making use of Anypoint MQ and demonstrating how to use MUnit to create significant tests for different scenarios. Using spy, verify call, assertions, mock, and more.

You can find the repo with the full code [here](https://github.com/alexandramartinez/my-process-api-munits).

{% embed https://www.twitch.tv/videos/2121384816 %}

## The flows

In summary, the main flow has a Subscriber to `queue1`. Once the message is processed, it's attempted to be sent in an HTTP Request to an **HR API**. The issue with this external API, is that it's not reliable and is often down. So, the code challenge was to be able to create a flow that could retry to send the RQ n amount of times before sending the message back to the queue. This was solved with an **Until Successful**.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2mvvd3y9ed6j65i9to6v.png)

The second issue is that not all errors should be interpreted or processed the same way. If the API returned a Connectivity error, the flow is supposed to keep trying. But what if it's not a connectivity error and it's a bad request or an internal server error? Then we don't want to keep trying with the same request over and over again. We want to discard it and send an error to the `queue2`.

For this, an Error Continue needed to be put in place.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4sn1b9hbj3tt72cqotng.png)

Now if the error is indeed a connectivity issue, then the error is returned with the **On Error Propagate** to the Until Successful so it can be tried again. But if the error is anything else, like a bad request, then the message is processed as an Error Response and is sent to the `queue2`.

This way, the Until Successful won't be tried again because the message is interpreted as a successful response, but the payload contains the error message.

## The tests

### Happy Path

The first test makes sure the happy path is working properly.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3wcasgbdntwyxum5o7j2.png)

There is a bunch of `Verify call` components that help us make sure certain components are executed exactly the number of times they're supposed to be executed. We also have `Mock`s for the calls to external systems, including Anypoint MQ.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rd5j3qdjuff7pkqxks39.png)

As you can see, none of the On Error Propagate/Continue were executed.

### Bad Request

As we learned from the description of the flows, we only want to keep trying to call the API if the error is a connectivity error. If not, we want to acknowledge the message from the queue and send the error response to the `queue2`.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p56ffzi39q74j6o3z1j5.png)

This test is a lot like the previous one. But take a look at the `Verify Call`s. Their numbers change.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4g1hmnnj6xshhlpvwl9e.png)

Now instead of creating the successful response, the flow went to the On Error Continue to create the error response and send it to `queue2`.

### Connectivity Issues 1

In this test, we are mocking the connectivity error from the API call so we can make sure that the Until Successful is exhausted and the queue message is being put back into the queue with the NACK.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f6bf5vparwiwvnsz5qh0.png)

As you can see, there are no assertions in this test. That is because we are expecting an error back from the main flow. Once the error reaches the test, the assertions are not executed. So how do we know this is the expected error? By configuring the error as expected from the test's configuration:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c48w53zk9oipcgylaobf.png)

This way, we are expecting to receive the `RETRY_EXHAUSTED` error from the Until Successful.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zl7p19cg1bobokm1xb36.png)

### Connectivity Issues 2

Another way to test the same error scenario, but with actual assertions, is with the Try/Catch scope.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zhu5gvybsj5bb23j7sh0.png)

This way, we are still making sure the `RETRY_EXHAUSTED` error is correctly being returned (and nothing else), and we are able to actually run some validations. Like making sure the API request and the On Error Propagate are being executed exactly 3 times (because of the Until Successful settings).