Testing your Azure Functions

Debugging your functions is not enough to guarantee that your code reacts appropriately to all the possible scenarios in which it is involved. Furthermore, you cannot automatically repeat the debug procedures every time part of your code changes.

Unit testing helps you. You can run your code automatically and consistently in a manner, covering all possible scenarios that your code might encounter.

Before we look at how to implement unit tests for your functions, it is important to clarify some definitions about unit testing.

Unit testing is a particular type of test where individual units/components of your code are tested. The purpose of the unit test is to validate that the behavior of a component is exactly the behavior of your design. 

Unit testing is the first type of test that you execute in the software development pipeline, and, generally, it is created and managed by the developer.

Implementing unit tests gives you the following benefits:

But unit tests also have the following disadvantages:

Of course, implementing unit tests is not simple, and you have to design your code to support them.

In the real world, your code will include references to external objects (for example, your methods could call external services or write to a database). In order to be unit testable, your code should be able to replace external references with components whose behavior is known. This is because, otherwise, your test will not only run on your code, but also on the code of external references, and this would mean that the code being tested is no longer unitary. So instead of these external resources, the code being tested uses friendly components. These friendly components are called mocks or stubs, and the way to use them is by using a mock library that helps you to create the mock components in a declarative way.

In the example snippet of this section, we will use the Moq library to implement these mocks, but, of course, you can use your favorite mock library.

Moq is an open source mocking library, and its repository is at https://github.com/moq/moq4.

If you look at one Azure Function signature, you can find the following dependencies:

To simplify, let's suppose we have the following function, which calculates a mortgage loan:

[FunctionName(FunctionNames.MortgageCalculatorFunction)]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
[Table("executionsTable", Connection = "StorageAccount")] ICollector<ExecutionRow> outputTable,
ILogger log)
{
// Code to retrieve info from the request and calculate the loan
}

The preceding code contains the following elements:

When the function runs in the runtime environment, all the parameter instances are managed by the runtime itself, but when you test the function, you can mock them because they are simple classes or instances of an interface.

An example of a unit test for the MortgageCalculatorFunction function you saw previously is as follows:

[Fact]
public async Task Run_RightParametersInQueryString_CalculateTheRate()
{
var request = new Mock<HttpRequest>();
request.Setup(e => e.Query["loan"]).Returns("100000");
request.Setup(e => e.Query["interest"]).Returns("0.06");
request.Setup(e => e.Query["nPayments"]).Returns("180");

var table = new Mock<ICollector<ExecutionRow>>();
table.Setup(t => t.Add(It.IsAny<ExecutionRow>()))
.Verifiable();

var logger = new Mock<ILogger>();

var actual = await MortgageFunctions.Run(request.Object, table.Object, logger.Object);

// Assert
}

The test is written using the xUnit.net test framework, but you can use your favorite testing engine.

xUnit.net is an open-source unit testing tool for .NET Framework. The official website is https://xunit.net/ and the GitHub repository is https://github.com/xunit/xunit.

The HTTP request, the collector, and the logger are mocked using the Moq library and are passed to the function. Of course, you have to set up all the mock methods that the function will call in the scenario you are testing (that is, in the previous sample, the method to access the query string of the request or the Add method of the ICollector<T>).

Mocking the parameters of the function is relatively simple, but what happens if you need to use your own service within your function? For example, let's suppose that the mortgage calculation algorithm is implemented within an instance of an interface (for example, IMortgageCalculator) and you need to use it inside the Run method. In this case, you cannot add the IMortgageCalculator in the function signature; otherwise, you will have an error (because it is neither a trigger nor a binding). To solve this, you have to use the dependency injection pattern in your Azure Function.