Before we go into the details of service virtualization, mocking and simulating systems communicating via RabbitMQ, let us see what RabbitMQ actually is.
RabbitMQ is an open-source message-broker software for asynchronous communication. You can send a message to a queue on a RabbitMQ broker. For example, System A can send a JSON message to RabbitMQ queue called QUEUE1. Then, System B can consume that message from QUEUE1 whenever it wishes to. System A and System B can communicate that way without a time dependency, System A can send messages as often and as many as it wishes, and System B can consume then whenever it is ready to do so.
For more details on RabbitMQ such as Exchanges, AMQP protocol details and others, please have a look at the RabbitMQ documentation.
Let us focus on a typical communication pattern where two systems communicate with request and response messages with a RabbitMQ broker. Although there are a few ways of implementing the request to response pattern (a reply queue per request, a single reply queue for multiple requests, etc.) for simplicity, we will use a single reply queue for multiple responses for this example.
Now that we have two systems communicating with RabbitMQ messages, we can explore how we could test those systems. What happens if we wanted to test System A, but System B is temporarily unavailable? Or, what happens if System B does not exist yet at all?
In these scenarios, we can simulate System B using Traffic Parrot so that System A can still be tested. It will consume the request messages and produce response messages, pretending to be System B.
This will allow us to test System A in isolation in both typical and hypothetical situations. You will be able to simulate messages that are expected to be seen in production environments, but also non-typical error messages or failure scenarios that would usually be hard to produce. You can do that by configuring Traffic Parrot to respond with RabbitMQ response messages of your choice.
Let's go through an example of how to use Traffic Parrot to simulate a system that sends and receives RabbitMQ messages. Our system under test is a Vegetable Ordering System that is used to send "order vegetable" messages, and an Order Processing System that receives an "order vegetable" message, processes the order and sends an "order confirmation" message.
Now, in our example, we will assume that the Order Processing System is not available (for example, it is not yet developed or the environment is not yet configured). All we have is the documentation for it. How can we test the Vegetable Ordering System in that situation, and where will the "order confirmation" messages come from if Order Processing System is not there?
We can simulate the Order Processing System using Traffic Parrot! Traffic Parrot will consume the order vegetable messages and send order confirmation messages, pretending to be the Order Processing System. We will read the Order Processing System documentation to understand how to define the format of the order confirmation messages.
NOTE: Traffic Parrot connects to RabbitMQ via a RabbitMQ JMS API, but your application can use any API to connect to RabbitMQ, it does not have to be JMS.
To simulate the Order Processing System using Traffic Parrot and test the Vegetable Order System in isolation follow these steps:docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.9-management
You can view the web user interface in the browser at http://localhost:8282.
The way the Vegetable Order System works is that you submit an order for a certain number of vegetable using the web user interface. It will then send a RabbitMQ request message to the Order Processing System. In the meantime it also awaits any RabbitMQ response messages and when it gets one it renders it on the web user interface. So when the Order Processing System is not available like in our scenario, there will never be anything displayed in the Order Confirmations section, but we still need to test that section!
{ "orderItemName": "carrot", "quantity": "5", "date": "2019-12-14T14:15:21Z" }Based on that documentation fill in the request queue name, response queue name and response body. Then, press the "Save" button.
{ "connectionId": "5", "connectionName": "Local RabbitMQ", "connectionData": { "jmsProvider": "RABBIT_MQ_3", "hostname": "localhost", "username": "guest", "password": "guest", "port": 5672, "amqpCompatibilityMode": true } }
The recommended way of creating mocks or stubs of third party or backed systems and APIs is
to keep them as simple as possible. Unfortunately, sometimes it is not
possible to keep things simple, and it is necessary to create more complex systems or API
simulators. In this example, we will go through an example how to create a simulator of an
RabbitMQ API that will dynamically generate a list of items in a response based on a request.
In the example above Traffic Parrot simulates the Order Processing System, but the RabbitMQ response message returned is always the same. So, regardless of what type of item and quantity we order the response message is always the same. Let us have a look at how to use Traffic Parrot to create a dynamic RabbitMQ response message!
To use request data in response we will use the handlebar helpers. We will use request.body to access the body of the RabbitMQ request message and then use jsonPath to extract bits of the JSON content {{jsonPath request.body '$.foo.bar'}}
To simulate the Order Processing System using Traffic Parrot and generate dynamic RabbitMQ response messages:{ "quantity": "5", "orderItemName": "carrot" }so we can now extract data and put it in the RabbitMQ response message using jsonPath like this
{{jsonPath request.body '$.quantity'}}and this
{{jsonPath request.body '$.orderItemName'}}We can also generate a dynamic date in the correct format using
{{now format="yyyy-MM-dd'T'HH:mm:ssZ"}}
{ "orderItemName": "{{jsonPath request.body '$.orderItemName'}}", "quantity": "{{jsonPath request.body '$.quantity'}}", "date": "{{now format="yyyy-MM-dd'T'HH:mm:ssZ"}}" }