Skip to content

Commit a4d4a78

Browse files
Merge pull request #298840 from wsilveiranz/wsilveiranz-LA-UnitTest-CreateFromRun
Create unit tests from a Standard workflow run in Azure Logic Apps with Visual Studio Code (Preview)
2 parents b34a9ce + a1e0598 commit a4d4a78

File tree

5 files changed

+369
-0
lines changed

5 files changed

+369
-0
lines changed
Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
---
2+
title: Create Unit Tests from Standard Workflow Runs with Visual Studio Code
3+
description: Create unit tests from previously run Standard workflows in Azure Logic Apps by using Visual Studio Code.
4+
services: logic-apps
5+
ms.suite: integration
6+
author: wsilveiranz
7+
ms.author: wsilveira
8+
ms.reviewer: estfan, azla
9+
ms.topic: how-to
10+
ms.date: 04/24/2025
11+
12+
---
13+
14+
# Create unit tests from Standard workflow runs in Azure Logic Apps with Visual Studio Code (Preview)
15+
16+
> [!NOTE]
17+
>
18+
> This capability is in preview and is subject to the
19+
> [**Supplemental Terms of Use for Microsoft Azure Previews**](https://azure.microsoft.com/support/legal/preview-supplemental-terms/).
20+
21+
Unit testing is an essential practice that keeps your app or solution reliable and accurate throughout the software development lifecycle. Unit tests help you efficiently and systematically validate the key components in your solution.
22+
23+
For Standard logic app workflows, you can create unit tests by using Visual Studio Code and the Azure Logic Apps (Standard) extension. This capability lets you use previously executed workflow runs to create unit tests and tailor them to scenarios supported by your logic app solution. This approach provides the following benefits:
24+
25+
- Reuse workflow runs to generate mock data for specific operations in the workflow.
26+
27+
This data lets you test workflows without having to call external services, systems, or APIs. You save time, and your workflow stays aligned with the actual workflow execution scenario.
28+
29+
- Improve workflow quality by identifying and addressing potential issues before you deploy to other environments.
30+
31+
- Streamline unit test integration with your development process, while ensuring consistent and accurate workflow behavior.
32+
33+
This guide shows how to create a unit test definition from a workflow run. This definition mocks the external calls from each workflow operation without changing the workflow logic. When you create a unit test from a workflow run, you get a unit test project that includes two folders:
34+
35+
- A folder that contains strongly-typed classes for each mockable operation in your workflow.
36+
37+
- A folder for each unit test definition, which includes the following files:
38+
39+
- A JSON file that represents the generated mocked operations in your workflow.
40+
41+
- A C# file that contains a sample class and methods that you use to set up your own assertions, confirm that the workflow behaves as expected, and make sure that the workflow behaves reliably and predictably in your larger Azure ecosystem.
42+
43+
## Prerequisites
44+
45+
- An Azure account and subscription. If you don't have a subscription, [sign up for a free Azure account](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
46+
47+
- A Standard logic app project in Visual Studio Code that contains at least one previously and locally executed workflow to use for creating a unit test.
48+
49+
For more information about Visual Studio Code setup and project creation, see [Create Standard logic app workflows with Visual Studio Code](/azure/logic-apps/create-standard-workflows-visual-studio-code).
50+
51+
### Limitations and known issues
52+
53+
- This release currently supports only C# for creating unit tests.
54+
55+
- This release doesn't support non-mocked actions. Make sure that all actions in the workflow execution path are mocked.
56+
57+
- This release doesn't support the following action types:
58+
59+
- Integration account actions
60+
- Data Mapper actions
61+
- Custom code actions
62+
- XML actions
63+
- Liquid actions
64+
- EDI encode and decode actions
65+
66+
## Review the basic concepts
67+
68+
The following list includes basic but important concepts about unit tests for Standard workflows:
69+
70+
- **Logic app unit test**
71+
72+
A controlled workflow execution that injects mock objects. These objects represent either the workflow trigger or actions that depend on external services or systems.
73+
74+
- **Mockable action**
75+
76+
A workflow action that depends on an external service or system. You can convert these actions to mocked actions for unit test creation and execution.
77+
78+
## Create a unit test from a workflow run
79+
80+
1. In Visual Studio Code, open your Standard logic app project.
81+
82+
1. On the Visual Studio Code toolbar, from the **Run** menu, select **Start Debugging**. (Keyboard: Press F5)
83+
84+
1. Return to the **Explorer** window. In your project, expand the workflow definition folder.
85+
86+
1. Open the **workflow.json** shortcut menu, and select **Overview**.
87+
88+
1. On the overview page, under **Run history**, select the workflow run to use for creating a unit test.
89+
90+
:::image type="content" source="media/create-unit-tests-standard-workflow-runs-visual-studio-code/overview-page.png" alt-text="Screenshot shows Visual Studio Code with Standard logic app project, debug mode running, opened workflow overview page, and selected workflow run." lightbox="media/create-unit-tests-standard-workflow-runs-visual-studio-code/overview-page.png":::
91+
92+
1. On the run history toolbar, select **Create unit test from run**.
93+
94+
:::image type="content" source="media/create-unit-tests-standard-workflow-runs-visual-studio-code/run-history-page.png" alt-text="Screenshot shows Visual Studio Code, Standard workflow run history page, and selected command to creat unit test." lightbox="media/create-unit-tests-standard-workflow-runs-visual-studio-code/run-history-page.png":::
95+
96+
1. Provide a name to use for the unit test, unit test class, and C# file.
97+
98+
In the **Explorer** window, a new project folder named **Tests** appears under your logic app project folder. The **Tests** folder contains the following folders and files:
99+
100+
:::image type="content" source="media/create-unit-tests-standard-workflow-runs-visual-studio-code/unit-test-project-structure.png" alt-text="Screenshot shows Visual Studio Code, Standard logic app project, and Tests folder with unit test folders and files." lightbox="media/create-unit-tests-standard-workflow-runs-visual-studio-code/unit-test-project-structure.png":::
101+
102+
| Folder or file | Description |
103+
|----------------|-------------|
104+
| **`Tests`** <br>**\|\| <`logic-app-name`>** | In the **`Tests`** folder, a **<`logic-app-name`>** folder appears when you add unit tests to a logic app project.|
105+
| **`Tests`** <br>**\|\| <`logic-app-name`>** <br>**\|\|\| <`workflow-name`>** | In the **<`logic-app-name`>** folder, a **<`workflow-name`>** folder appears when you add unit tests for a workflow. |
106+
| **`Tests`** <br>**\|\| <`logic-app-name`>** <br>**\|\|\| <`workflow-name`>** <br>**\|\|\|\| `MockOutputs`** <br>**\|\|\|\|\| <`operation-name-outputs`>**.**`cs`** | In the **<`workflow-name`>** folder, the **`MockOutputs`** folder contains a C# (**.cs**) file with strongly-typed classes for each connector operation in the workflow. Each **.cs** file name uses the following format: <br><br>**<`operation-name`>[`Trigger\|Action`]`Output.cs`** <br><br>If a connector operation has *dynamic contracts*, a class appears for each *dynamic type*. A dynamic type refers to an operation parameter that has different inputs and outputs based on the value provided for that parameter. You can use these classes to extend your unit tests and create new mocks from scratch. |
107+
| **`Tests`** <br>**\|\| <`logic-app-name`>** <br>**\|\|\| <`workflow-name`>** <br>**\|\|\|\| <`unit-test-name`>** <br>**\|\|\|\|\| <`unit-test-name`>`-mock.json`** <br>**\|\|\|\|\| <`unit-test-name`>`.cs`** | In the **<`workflow-name`>** folder, the **<`unit-test-name`>** folder contains the following files: <br><br>- The **<`unit-test-name`>`-mock.json`** file contains a JSON representation for the generated mocks, based on the workflow run that created the unit test. <br><br>- The **<`unit-test-name`>`.cs`** file contains a sample C# class and methods that use the **`*-mock.json`** file to run and assert results. You can edit this file to match your specific test scenarios. |
108+
109+
## Review the *-mock.json file
110+
111+
This file has the following main sections:
112+
113+
### `triggerMocks` section
114+
115+
The **`triggerMocks`** section contains the mocked result from the workflow trigger. This section is required to start workflow execution as shown in the following example:
116+
117+
```json
118+
{
119+
"triggerMocks": {
120+
"When_messages_are_available_in_a_queue_(peek-lock)": {
121+
"name": "When_messages_are_available_in_a_queue_(peek-lock)",
122+
"status": "Succeeded",
123+
"outputs": {
124+
"body": {
125+
"contentData": {
126+
"messageId": "1234",
127+
"status": "new",
128+
"contentType": "application/json",
129+
"userProperties": {},
130+
"scheduledEnqueueTimeUtc": "1/1/0001 12:00:00 AM",
131+
"timeToLive": "14.00:00:00",
132+
"deliveryCount": 1,
133+
"enqueuedSequenceNumber": 0,
134+
"enqueuedTimeUtc": "2025-04-07T01:10:09.738Z",
135+
"lockedUntilUtc": "2025-04-07T01:11:09.769Z",
136+
"lockToken": "78232fa8-03cf-4baf-b1db-3375a64e0ced",
137+
"sequenceNumber": 5
138+
}
139+
}
140+
}
141+
}
142+
},
143+
"actionMocks": {...}
144+
}
145+
```
146+
147+
### `actionMocks` section
148+
149+
For each mockable action in a workflow run, the **`actionMocks`** section contains a mocked action and guarantees the controlled execution of the workflow.
150+
151+
152+
```json
153+
{
154+
"triggerMocks": {...},
155+
"actionMocks": {
156+
"Call_External_API": {
157+
"name": "Call_External_API",
158+
"status": "Succeeded",
159+
"outputs": {
160+
"statusCode": 200,
161+
"body": {
162+
"status": "Awesome!"
163+
}
164+
}
165+
},
166+
"CompleteMessage": {
167+
"name": "CompleteMessage",
168+
"status": "Succeeded",
169+
"outputs": {
170+
"statusCode": "OK",
171+
"body": {}
172+
}
173+
}
174+
}
175+
}
176+
```
177+
178+
## Review the unit test *.cs file
179+
180+
This unit test class provides a framework for testing Standard logic app workflows by mocking triggers and actions. This class lets you test workflows without actually calling external services or APIs.
181+
182+
### Test class structure
183+
184+
A typical unit test class uses the following structure:
185+
186+
```csharp
187+
[TestClass]
188+
public class <unit-test-name>
189+
{
190+
public TestExecutor TestExecutor;
191+
192+
[TestInitialize]
193+
public void Setup()
194+
{
195+
this.TestExecutor = new TestExecutor("<workflow-name>/testSettings.config");
196+
}
197+
198+
// Add test methods here.
199+
200+
// Add helper methods here.
201+
}
202+
```
203+
204+
#### Setup() method
205+
206+
This method instantiates the **`TestExecutor`** class by using the path to your test settings configuration file. The method runs before each test execution and creates a new instance of **`TestExecutor`**.
207+
208+
```csharp
209+
[TestInitialize]
210+
public void Setup()
211+
{
212+
this.TestExecutor = new TestExecutor("<workflow-name>/testSettings.config");
213+
}
214+
```
215+
216+
### Sample test methods
217+
218+
The following section describes sample test methods that you can use in your unit test class.
219+
220+
#### Static mock data test
221+
222+
The following method shows how to use static mock data to test your workflow. In this method, you can complete the following tasks:
223+
224+
- Set property values on your mocked actions.
225+
- Execute the workflow with the configured mock data.
226+
- Confirm that the execution succeeded.
227+
228+
```csharp
229+
[TestMethod]
230+
public async Task <workflow-name>_<unit-test-name>_ExecuteWorkflow_SUCCESS_Sample1()
231+
{
232+
// PREPARE mock: Generate mock action and trigger data.
233+
var mockData = this.GetTestMockDefinition();
234+
var sampleActionMock = mockData.ActionMocks["Call_External_API"];
235+
sampleActionMock.Outputs["your-property-name"] = "your-property-value";
236+
237+
// ACT: Create the UnitTestExecutor instance. Run the workflow with mock data.
238+
var testRun = await this.TestExecutor
239+
.Create()
240+
.RunWorkflowAsync(testMock: mockData).ConfigureAwait(continueOnCapturedContext: false);
241+
242+
// ASSERT: Confirm successful workflow execution and that the status is 'Succeeded'.
243+
Assert.IsNotNull(value: testRun);
244+
Assert.AreEqual(expected: TestWorkflowStatus.Succeeded, actual: testRun.Status);
245+
}
246+
```
247+
248+
#### Dynamic mock data test
249+
250+
The following method shows how to use dynamic mock data with callback methods. This approach gives you two options that dynamically generate mock data:
251+
252+
- Define a separate callback method.
253+
- Use an [inline lambda function](/dotnet/csharp/language-reference/operators/lambda-expressions).
254+
255+
Both approaches let you create dynamic responses based on unit test execution context.
256+
257+
```csharp
258+
[TestMethod]
259+
public async Task <workflow-name>_<unit-test-name>_ExecuteWorkflow_SUCCESS_Sample2()
260+
{
261+
// PREPARE: Generate mock action and trigger data.
262+
var mockData = this.GetTestMockDefinition();
263+
264+
// OPTION 1: Define a callback class.
265+
mockData.ActionMocks["Call_External_API"] = new CallExternalAPIActionMock(
266+
name: "Call_External_API",
267+
onGetActionMock: CallExternalAPIActionMockOutputCallback);
268+
269+
// OPTION 2: Define an inline lambda function.
270+
mockData.ActionMocks["Call_External_API"] = new CallExternalAPIActionMock(
271+
name: "Call_External_API",
272+
onGetActionMock: (testExecutionContext) =>
273+
{
274+
return new CallExternalAPIActionMock(
275+
status: TestWorkflowStatus.Succeeded,
276+
outputs: new CallExternalAPIActionOutput {
277+
278+
// If this account contains a JObject Body,
279+
// set the properties you want here:
280+
// Body = "something".ToJObject()
281+
282+
}
283+
);
284+
});
285+
286+
// ACT: Create UnitTestExecutor instance. Run the workflow with mock data.
287+
var testRun = await this.TestExecutor
288+
.Create()
289+
.RunWorkflowAsync(testMock: mockData).ConfigureAwait(continueOnCapturedContext: false);
290+
291+
// ASSERT: Confirm successful workflow execution and that the status is 'Succeeded'.
292+
Assert.IsNotNull(value: testRun);
293+
Assert.AreEqual(expected: TestWorkflowStatus.Succeeded, actual: testRun.Status);
294+
}
295+
```
296+
297+
#### Error scenario test
298+
299+
The following method shows how to test failure conditions. In this method, you can complete the following tasks:
300+
301+
- Configure mocked actions to fail with specific error codes and messages.
302+
- Confirm that the workflow handles these error conditions correctly.
303+
304+
```csharp
305+
[TestMethod]
306+
public async Task <workflow-name>_<unit-test-name>_ExecuteWorkflow_FAILED_Sample3()
307+
{
308+
// PREPARE: Generate mock action and trigger data.
309+
var mockData = this.GetTestMockDefinition();
310+
var mockError = new TestErrorInfo(code: ErrorResponseCode.BadRequest, message: "Input is invalid.");
311+
mockData.ActionMocks["Call_External_API"] = new CallExternalAPIActionMock(
312+
status: TestWorkflowStatus.Failed,
313+
error: mockError);
314+
315+
// ACT: Create UnitTestExecutor instance. Run the workflow with mock data.
316+
var testRun = await this.TestExecutor
317+
.Create()
318+
.RunWorkflowAsync(testMock: mockData).ConfigureAwait(continueOnCapturedContext: false);
319+
320+
// ASSERT: Confirm successful workflow execution and that the status is 'Succeeded'.
321+
Assert.IsNotNull(value: testRun);
322+
Assert.AreEqual(expected: TestWorkflowStatus.Failed, actual: testRun.Status);
323+
}
324+
```
325+
326+
### Helper methods
327+
328+
The following section describes methods used by the sample test methods. Helper methods appear under the test methods in the class definition.
329+
330+
#### GetTestMockDefinition()
331+
332+
The following method loads the mock definition from a JSON file. You can edit this method if your mock data is stored in a different location or format.
333+
334+
```csharp
335+
private TestMockDefinition GetTestMockDefinition()
336+
{
337+
var mockDataPath = Path.Combine(TestExecutor.rootDirectory, "Tests", TestExecutor.logicAppName,
338+
TestExecutor.workflow, "<unit-test-name>", "<unit-test-name>-mock.json");
339+
return JsonConvert.DeserializeObject<TestMockDefinition>(File.ReadAllText(mockDataPath));
340+
}
341+
```
342+
343+
#### Callback method
344+
345+
The following method dynamically generates mock data. The method name varies based on the mocked action name in the test methods for static or dynamic mock data. You can edit this method to return different mock responses based on your test scenario requirements or use it as a template to create your own dynamic callback methods.
346+
347+
```csharp
348+
public CallExternalAPIActionMock CallExternalAPIActionMockOutputCallback(TestExecutionContext context)
349+
{
350+
// Sample mock data: Dynamically change the mocked data for "actionName".
351+
return new CallExternalAPIActionMock(
352+
status: TestWorkflowStatus.Succeeded,
353+
outputs: new CallExternalAPIActionOutput {
354+
355+
// If this account contains a JObject Body,
356+
// set the properties you want here:
357+
// Body = "something".ToJObject()
358+
359+
}
360+
);
361+
}
362+
```
363+
364+
## Related content
365+
366+
[Create unit tests from Standard workflow definitions in Azure Logic Apps with Visual Studio Code](/azure/logic-apps/create-unit-tests-Standard-workflow-definitions-visual-studio-code)
367+
60.9 KB
Loading
23.7 KB
Loading
Loading

articles/logic-apps/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,8 @@ items:
465465
items:
466466
- name: Create unit tests from Standard workflow definitions
467467
href: create-unit-tests-standard-workflow-definitions-visual-studio-code.md
468+
- name: Create unit tests from Standard workflow runs
469+
href: create-unit-tests-standard-workflow-runs-visual-studio-code.md
468470
- name: Test workflows with mock outputs
469471
href: test-logic-apps-mock-data-static-results.md
470472
- name: Deploy

0 commit comments

Comments
 (0)