Skip to content

Setting up a Test

MarkAbrams edited this page Dec 22, 2023 · 6 revisions

A workflow test is executed using an implementation of ITestRunner. This is created using the CreateTestRunner() method from the base class:

[TestMethod]
public void WorkflowTest()
{
    using (ITestRunner testRunner = CreateTestRunner())
    {

An instance of ITestRunner should only be used for a single test.

Configure Mocked Responses

The next step is to configure the responses for the requests that are sent to the mock HTTP server. There are two ways to do this:

  • Configure Request Matchers and Response Builders using a fluent API
  • Configure a delegate function that creates the responses, based on the HTTP request

A test case can use either of these methods, or both. If both methods are used, the testing framework will firstly evaluate the Request Matchers configured using the fluent API. If a request is not matched, the delegate function is called. If a request is matched, the corresponding fluent Response Builder is used and the delegate function is not called.

If a request is not matched using the fluent API and the delegate function returns null, a default HTTP response is created by the testing framework. The default response has no content and a HTTP status code that is configured using the runner.defaultHttpResponseStatusCode option in the testConfiguration.json file. If the runner.defaultHttpResponseStatusCode option is not set in the testConfiguration.json file, the default status code is HTTP 200 (OK).

The preferred method for configuring responses is the fluent API because creating request matchers and configuring responses using the fluent API is more intuitive and structured than writing a delegate function. Future versions of LogicAppUnit will include additional request matching functionality that will only be available using the fluent API. However, there may be scenarios when you need the flexability of writing a delegate function and this is why the testing framework supports both methods in a test case.

Order of Evaluation

Fluent Request Matchers can be configured in two places:

  • In a test case.
  • In a test class Initialization method.

If you have many test cases in a test class and you want to configure some Fluent Request Matchers for all tests in the class, just define the Request Matchers once, in the test class Initialization method. They will then be used by all test cases in the test class.

When a test case is run, the test runner evaluates Fluent Request Matchers and the delgate function in this order (highest priority is first):

  1. Fluent Request Matchers configured in the test case.
  2. Fluent Request Matchers configured in the test class Initialization method.
  3. Delegate function configured in the test case.

Fluent API

Configuration of Request Matchers and Response Builders using the Fluent API is described in a separate section.

Delegate Function

The delgate function is configured in a test case using the TestRunner.AddApiMocks() property. The delegate function must return an instance of HttpResponseMessage, or null. This example mocks the responses for workflow actions that connect to SQL Server and Service Bus:

// Mock the SQL and Service Bus actions and customize responses
// For both types of actions, the URI in the request matches the action name
testRunner.AddApiMocks = (request) =>
{
    HttpResponseMessage mockedResponse = new HttpResponseMessage();
    if (request.RequestUri.AbsolutePath == "/Execute_Query_to_get_Language_Name")
    {
        mockedResponse.RequestMessage = request;
        mockedResponse.StatusCode = HttpStatusCode.OK;
        mockedResponse.Content = ContentHelper.CreateJsonStringContent(GetSqlExecuteResponseContent());
    }
    else if (request.RequestUri.AbsolutePath == "/Send_message_to_Topic")
    {
        // No response content for Service Bus actions
        mockedResponse.RequestMessage = request;
        mockedResponse.StatusCode = HttpStatusCode.OK;
    }
    return mockedResponse;
};

The HTTP request is passed to the delegate function as a parameter of type HttpRequestMessage. You can use any of the request properties to match the request with a response, for example request.RequestUri.AbsolutePath to match based on the request URI.

The ContentHelper class is part of the testing framework and contains methods that are useful when creating HTTP content (JSON, XML and plain text) for the mocked responses.

Creating Call-Back URLs

You may have a workflow which receives a message that contains a callback URL and the workflow then makes a HTTP request using the callback URL. For example, a workflow may be triggered by an event notification, and the workflow uses the callback URL in the notification to read the details of the changed object.

The callback URL must be a URL pointing at the mock HTTP server, otherwise the test framework cannot "see" the request (because it will be sent somewhere else). To implement the test correctly, the base URL and port in the callback URL must refer to the mock HTTP server. You can get the URL for the mock HTTP server using the WorkflowTestBase.MockTestWorkflowHostUri property.

This example shows a method in a test class (that inherits from WorkflowTestBase) that creates an event trigger. The code uses the MockTestWorkflowHostUri property and string interpolation to create a value for resourceURI which is a callback URL:

public static StringContent CreateTriggerRequest()
{
    return ContentHelper.CreateJsonStringContent(new
    {
        id = "019aaf01-19ee-424c-94f0-ae5c00a8e677",
        correlationId = "9b6f8da4-13eb-48ac-851c-ae5c00a8e671",
        sourceSystem = "SystemOne",
        timestamp = "2022-03-18T10:14:56.8012126Z",
        type = "CustomerCreated",
        customerId = 12345,
        resourceId = "12345",
        resourceURI = $"{MockTestWorkflowHostUri}/api/v2/customer/12345"
    });
}

The value of the MockTestWorkflowHostUri property depends on the platform that is being used (Windows, Linux or MacOS). For Windows it will be http://<machine name>:7075, for Linux and MacOS it will be http://localhost:7075.

Clone this wiki locally