Skip to content

Checking the Workflow Run

MarkAbrams edited this page Oct 24, 2023 · 2 revisions

You can check (assert) the workflow run status using the TestRunner.WorkflowRunStatus property:

// Check workflow run status
Assert.AreEqual(WorkflowRunStatus.Succeeded, testRunner.WorkflowRunStatus);

The TestRunner.WorkflowRunId property will give you the workflow's Run Id:

// Get the Run Id
string runId = testRunner.WorkflowRunId;

You can check the response from the workflow:

// Check workflow response
Assert.AreEqual(HttpStatusCode.Unauthorized, workflowResponse.StatusCode);
Assert.AreEqual("Invalid authorization header passed", workflowResponse.Content.ReadAsStringAsync().Result);
Assert.AreEqual("text/plain; charset=utf-8", workflowResponse.Content.Headers.ContentType.ToString());

You can check the status of individual actions in the workflow run history using the TestRunner.GetWorkflowActionStatus(string actionName) method, passing the action name as the parameter:

// Check action result
Assert.AreEqual(ActionStatus.Skipped, testRunner.GetWorkflowActionStatus("Unauthorized_Response"));
Assert.AreEqual(ActionStatus.Failed, testRunner.GetWorkflowActionStatus("Get_Customer_Details_from_Service_One"));
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Failed_Get_Response"));
Assert.AreEqual(ActionStatus.Skipped, testRunner.GetWorkflowActionStatus("Update_Customer_Details_in_Service_Two"));

Make sure the action name in the test matches the action name in the workflow.json file, i.e. spaces replaced with underscores. The testing framework will not automatically replace spaces with underscores.

You can also check the workflow's Client Tracking Id using the TestRunner.WorkflowClientTrackingId property:

// Check the Client Tracking Id
Assert.AreEqual("expected-tracking-id", testRunner.WorkflowClientTrackingId);

Repeating Actions

The testing framework supports the checking of actions that run inside a loop, for example an Until loop or a ForEach loop.

You can check the status of individual action repetitions in the workflow run history using the TestRunner.GetWorkflowActionStatus(string actionName, int repetitionNumber) method, passing the action name and repetition number as parameters:

// Check action result
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Call_Service", 3));
Assert.AreEqual(ActionStatus.Failed, testRunner.GetWorkflowActionStatus("Call_Service", 4));
Assert.AreEqual(ActionStatus.Succeeded, testRunner.GetWorkflowActionStatus("Call_Service", 5));

In this example we expect the Call_Service action in the third and fifth repetitions to be successful and the fourth repetition to fail.

Make sure the action name matches the action name in the workflow.json file, i.e. spaces replaced with underscores.

You can also check the total number of repetitions for an action in a loop, and check the number of iterations for the loop itself:

// The 'Call_Service' action is inside of the 'Loop_for_each_iteration' loop
Assert.AreEqual(5, testRunner.GetWorkflowActionRepetitionCount("Loop_for_each_iteration"));
Assert.AreEqual(5, testRunner.GetWorkflowActionRepetitionCount("Call_Service"));

Checking Action Input and Output Messages

You can check the input and output messages for an action using the TestRunner.GetWorkflowActionInput(string actionName) and TestRunner.GetWorkflowActionOutput(string actionName) methods, passing the action name as the parameter:

// Check input and output messages for Parse action
JToken parseCustomerInput = testRunner.GetWorkflowActionInput("Parse_Customer");
JToken parseCustomerOutput = testRunner.GetWorkflowActionOutput("Parse_Customer");

Use the method overloads for action repetitions that run in a loop:

// Get input and output messages for the second repetition
JToken serviceOneInput2 = testRunner.GetWorkflowActionInput("Call_Service_One", 2);
JToken serviceOneOutput2 = testRunner.GetWorkflowActionOutput("Call_Service_One", 2);

The response is a JToken that includes the details of the input and output for the action, including the input and output message bodies. The structure of the JSON and the attributes in the JToken depends on the type of action. This example validates fields in the JSON output of a Compose action:

// Validate Customer request
JToken composeCustomerRequestOutput = testRunner.GetWorkflowActionOutput("Compose_Customer_Request");
Assert.IsNotNull(composeCustomerRequestOutput);
Assert.AreEqual(composeCustomerRequestOutput["data"]["name"].Value<string>(), "Peter Smith");
Assert.AreEqual(composeCustomerRequestOutput["data"]["address"]["line1"].Value<string>(), "23 High Street");

Checking HTTP requests in the Mock Server

You can also check the requests sent to the mock HTTP server, using the TestRunner.MockRequests property which returns a List<MockRequest>:

// Check request to Membership API
MockRequest request = testRunner.MockRequests.First(r => r.RequestUri.AbsolutePath == "/api/v1.1/membership/customers/1234");
Assert.AreEqual(HttpMethod.Put, request.Method);
Assert.AreEqual("application/json", request.ContentHeaders["Content-Type"].First());
Assert.AreEqual("expected-api-key", request.Headers["x-api-key"].First());
Assert.AreEqual(
    ContentHelper.FormatJson(ResourceHelper.GetAssemblyResourceAsString($"{GetType().Namespace}.MockData.ExpectedRequest.json")),
    ContentHelper.FormatJson(request.Content));

The instances of MockRequest in the list are sorted in chronological ascending order.

The ContentHelper.FormatJson() method is part of the testing framework and formats JSON into a consistent format to enable reliable string comparison between the actual request and the expected request. ContentHelper.FormatXml() can be used for the comparison of XML.

The input message for a HTTP action should match the request message that is recorded by the mock HTTP server and the same applies to the action's output message and the response that is created by the mock HTTP server. The testing framework lets you use either or both of these approaches for your test cases.

Checking Tracked Properties

You can check the tracked properties for an action using the TestRunner.GetWorkflowActionTrackedProperties(string actionName) method, passing the action name as the parameter:

// Check tracked properties
Dictionary<string, string> trackedProps = testRunner.GetWorkflowActionTrackedProperties("Get_Customer");
Assert.AreEqual("customer", trackedProps["recordType"]);
Assert.AreEqual("123456", trackedProps["recordId"]);
Assert.AreEqual("c2ddb2f2-7bff-4cce-b724-ac2400b12760", trackedProps["correlationId"]);

Use the method overload for action repetitions that run in a loop:

// Check tracked properties for the fourth repetition
Dictionary<string, string> trackedProps = testRunner.GetWorkflowActionTrackedProperties("Get_Customer", 4);

Stateless workflows do not record the tracked properties in the workflow run history, even when the run history is enabled using the OperationOptions setting. Therefore the GetWorkflowActionTrackedProperties() method will always return null for actions in a stateless workflow.

Checking Terminated Workflows

The workflow Terminate action is used to stop the run for a workflow instance, cancelling any actions that are in progress and skipping any remaining actions. The workflow action is configured with a status (Failed, Cancelled or Succeeded) and an error code and message when the status is Failed.

You can check if a workflow was terminated using the the TestRunner.WorkflowWasTerminated property. This will return true if the workflow run was stopped because of a Terminate action. In all other cases it will return false.

// Check if the workflow was terminated
Assert.IsTrue(testRunner.WorkflowWasTerminated);

If a workflow was terminated with a Failed status, you can check the termination error code and message using the TestRunner.WorkflowTerminationCode and TestRunner.WorkflowTerminationMessage properties:

// Check termination error code and message
Assert.AreEqual((int)HttpStatusCode.InternalServerError, testRunner.WorkflowTerminationCode);
Assert.AreEqual("Language Code 'xx-GB' is not valid", testRunner.WorkflowTerminationMessage);

If the workflow was not terminated, or terminated with a status of Cancelled or Succeeded, these two properties will return null.

If a workflow uses a HTTP trigger and includes a HTTP Response action, and the workflow is terminated before the HTTP response action, the workflow response status code will be HTTP 502 (Bad Gateway). This is because the Terminate action will stop the workflow run and the HTTP Response action will never be called, resulting in no HTTP response being returned to the caller - which in this instance is the test case.

Clone this wiki locally