In a recent Azure Logic Apps release, the Azure Logic Apps team deployed a new feature that allows a developer to test their logic app using mock data. The feature has been called Static results and aims at enabling developers to build more robust logic apps. Having more predictable logic/code is always a good thing as it increases the quality of the end product, or service, that you are delivering.
Mocking endpoints is certainly nothing new, but it can take a lot of effort to set up and maintain, especially if you are coding services or APIs manually. Using the Static result feature is quick and easy to set up and does not require any additional services or 3rd party dependencies.
The example we will explore in this post is an apartment rental, customer service scenario. A customer, or tenant, contacts their apartment’s customer service department to log a ticket to have some maintenance work completed in their apartment unit. A customer service representative logs the request in their CRM system and dispatches a work order to a field technician. The field technician performs the work and closes the work order. We want to inform the customer that their work order has been completed by sending an email once the work is complete.
Since the CRM system contains real data, it becomes difficult to test this logic app in a safe and efficient manner. Ideally, you have a “shadow” copy of this database, or system, where you have all of the underlying data structures in place and perhaps even masked, or anonymized data so that you can do some testing. If you have all of this, great, but it takes a lot of work to get there.
Some organizations will test these scenarios by having a ‘fake’ customer in their system where they can perform this testing against this user. This also works, but you generally discourage creating ‘fake’ data in a production system from a compliance (SOX) perspective. If you don’t have either of these options, then you have a real challenge.
Previously, you may have included conditions in your logic app, to accommodate some level of testing. You may have a flag set in a variable, at the top of your logic app, that when set will perform some test functions. For example, you may execute all of your steps except the last one that includes sending the customer an email. But, with the new Static result feature in Logic Apps, the entire process is much simpler.
Logic App Design
First, let’s take a look at our logic app design and then we will get into how we can test this logic app using Static results. Our design is as follows:
- Start with a Recurrence trigger that will run at the end of the workday.
- We will then call a SQL stored procedure that will retrieve today’s work orders and pass in today’s date using an expression of utcNow(‘yyyy-MM-dd’).
- Then have a For each action will take the customer Id from the work order and then get more details about the customer by passing in the customer Id to get more details about the customer including their email address.
- Technically, the stored procedure can return an array of records so another For each is automatically added to our logic app, even though we only have one customer record being returned.
- We will then send an email using the com connector to the customer as their email address is included in the customer record.
Let’s now go down a Happy Path, where we expect our test results to always be successful. To support this path, we need to enable Static results on the actions that we want to ‘mock test’. We will start with our Get Todays Work orders action by clicking on the ellipsis (…) and then clicking on Static result (Preview).
We now need to Enable Static Result by flipping the toggle switch and then click on Done.
We will have the default configuration. Here we have the ability to check our Status which is set to Succeeded which works well for our Happy Path test. In addition, our Status Code is set to OK which is what we would expect in a happy path scenario.
Do note, there is an extensive list of Status Codes that can be returned including MethodNotAllowed, RequestTimeout, 200, 201, 202, 403, 404, 500 and many, many more. It is important to note that when we specify a value here, it is the value we expect the Static result to return.
We can now click on Done and observe the default behavior of this feature.
Within the Logic Apps designer, we will discover an orange beaker icon is now present for the action that we have enabled Static results for.
Let’s now run our logic app and observe the behavior.
We can see that our action succeeds and if we look at the Outputs we will discover that our Status code of OK is returned. However, we don’t have any records included in our response. This is an issue.
Because we do not have a message body being returned from our Get Todays Work orders action, our next step actually fails. As a result, we need to provide a mock message body response in our Static results configuration.
To provide sample outputs, we need to enable JSON Mode by clicking on the T icon. Be aware that this icon appears in multiple sections, so be sure that you are clicking on the correct instance of the icon. Since we are interested in modifying our Output we need to click on the icon in the Output section.
We will have the sample output, but we can overwrite it by taking an output from a prior logic app execution from our run history.
In our actual execution, the Status Code returned was 200 so I have updated that. In addition, I have included a message body object which represents my JSON response. Ensure you do not include quotes around this body object as logic apps will interpret it as a string and your downstream action(s) will not process it properly.
If we run our logic app again, we will see that we are now passing results from our mock action and our downstream actions are able to use these outputs as inputs into their operations. Here is the input for our next action Get Customer By Id.
Let’s now update our remaining actions to also use mocked inputs.
Here is the Static results configuration for our next action, Get Customer By Id.
Now one thing to note is that we have a situation where our logic app is currently returning multiple work orders from our initial call to retrieve today’s work orders. We then have a loop that for each work order that we need to retrieve a customer. In this situation, when we provide mocked inputs, we can’t provide an index of which customer node to use from our work order response. As a result, we have the same input being used for each work order that has been returned from our previous action.
The last action that we need to mock is our Outlook action. In this case, we are not expecting data to be returned outside of a statusCode of 200. The additional information that I have included comes from the Headers returned from our runtime call, but doesn’t have any significant impact on our scenario.
With all of our actions now mocked, let’s go ahead and run our logic app once again. We can see that our logic app executes successfully and that we have our core actions enabled for Static results.
Before we test a negative path, let’s explore what changes have been made to our logic app under the hood. The first thing to notice is in our Run history, we have a column visible called Static Results. During regular operations, the value displayed is Disabled. However, once we enable Static results, we will see this value is Enabled. So this naturally brings up an important consideration. While testing your logic app, if you receive “legitimate” traffic during this time, any actions that have Static results will return mocked data. There is currently no way of dynamically injecting a value that directs Logic Apps to use a mocked or real endpoint.
In addition, let’s take a look at our ‘code behind’. We will discover that for our actions that have Static results enabled, we have a flag called staticResultOptions that is set to Enabled.
In addition, we will find a staticResults section in our code definition where our mocked data is stored. This ultimately means that our mocked data moves with our logic app code. This serves as a reminder not to include sensitive or customer data that could be subject to GDPR within these files.
Interestingly enough, during the testing of this blog solution, I ran into the transient error with the Outlook.com connector. This exposes a use case that we should code for.
Let’s modify our flow to capture this scenario. Let’s change our Static results to include a Status of Failed, provide an Error Message and update our statusCode to be 403.
Next, let’s add another action to log the failure. For our purposes let’s just call an HTTP log service.
Since we only want this action to run when we have a failure, let’s Configure run after settings. For more information on Configure run after settings, please refer to this Serverless360 community knowledge base.
We only want the HTTP action to run when our Outlook.com action has failed.
Let’s now go and run our logic app again. As expected, because we changed our Static result to return a 403 exception with a status of Failed, our Configure run after settings kicked in and routed the exception to our HTTP action that will only run when we have a failed run.
If we navigate to our code-behind, we will discover that our Static Results definition has been updated to include our error condition for our Send an email V2 action. As a result, our Happy path configuration has been removed. Something to consider as you are building out your test scenarios.
In this post, we discussed using a recent Static results feature that allows developers to mock-up responses from specific actions. This allows developers to build out higher quality logic apps, as a result of scenario-based testing.
One area of opportunity is allowing for different ‘profiles’ to use or to support a collection of tests. Currently, you can include only 1 scenario per action. As a result, you end up creating copies of your logic apps in order to build out multiple positive or negative path scenarios. You certainly do not want to have multiple copies of your logic app, so this creates a constraint on how many different testing paths you can support.
Also, having the ability to dynamically turn this Static result feature on or off, would be interesting as it would allow for the simultaneous testing of your logic app, but also allowing legitimate messages through your logic app as well. Currently, it is binary, on or off. As a result, trying to use this in a continuous integration scenario becomes more difficult as you have to alter your logic app definition at deployment time. Probably not that big of a deal, but also introduces changes which lead to additional edge cases and potential regression issues.