Testing Azure functions with a twist

Cheranga Hatangala
Cheranga
Published in
4 min readSep 11, 2020

--

Introduction

As in any other application, testing Azure functions are utmost important.

Unit tests are targeted towards only a narrowed down aspect of the whole picture (as it should be anyways). Integration tests as per the name actually verifies how two or more components behave when integrated.

But what if?

  • We would like to test our functions without having to inject a whole lot of mocks and their respective setups of methods and properties.
  • We don’t want to run tests after the code has been deployed as an integration test in the pipeline but rather in our build pipeline itself before deployment?
  • We would like to have the flexibility to inject different dependencies at the function start up (based on cost factors, security reasons, etc…) itself so that the Azure functions will use the overridden dependencies from tests?
  • We don’t want to complicate the test project and also the CI/CD pipelines with additional tasks to install function runtime and starting and stopping it.

Though, in a previous article I have explained how we can install a function runtime and do integration tests, but in here I don’t want to install any function runtime, but still would like to test the functions as they would really behave.

What are we building and testing?

Customer Registration

As illustrated we’ll create an HTTP triggered Azure function to register customers. We’ll use another API called “Categorization API” to categorize the customer. Based on the categorization the customer data will be saved in respective BLOB containers (VIP or Regular customers)

The code for this article can be found in GitHub.

The HTTP triggered Azure function

All the required dependencies are injected to the function. As you can see it accepts an HTTP POST request and, calls the CategorizeCustomerService which abstracts the calling to the external API. Depending on the result it’ll use another abstraction BlobService to create the BLOBs in their respective containers.

Dependency Injection!

Azure functions support dependency injection. You can add a start up class and then configure it to register all your dependencies where the Azure functions will be using.

But in our case we would like the configuration provider to be overridden by our tests. Please see below how we can configure our Startup class in the Azure function project to have this functionality.

The GetConfigurationRoot method sets up the different configuration providers. In there we use the local.settings.json (when running the function in the local developer environment) and of course let them be overridden by the environment variables when deployed to Azure.

Inside the Configure method We use different sections of the configuration settings to load and bind the values to strongly typed objects. In Azure functions the configurations are mere name value pairs, you cannot have complex JSON structures in there. But if you would like to specify and load the settings in a modular fashion please read this article where I explain how you’ll be able to do that.

The local.settings.json file

The above are the configuration changes which you can keep in the local development environment. But obviously these values will be overridden once the code is deployed in Azure. Please note that the value in CustomerApiConfig:URL . Assume this is the URL that you use to categorize the customers when this is actually deployed in Azure.

The Test Project

Now let’s see how we can tweak the configurations and let Azure functions to use them.

As you can see inside the Configure method if you would like you can override the dependencies to point to test related abstractions. Also in the GetConfigurationRoot method you can setup your own test settings in anyway you like. But to keep things concise, I am maintaining a local.settings.json file in the test project as well and, as shown below the CustomerApiConfig:Url is now pointing to “https://www.microsoft.com”.

The Tests

Since we have BLOB creation operations to test, we can use a nuget package called RimDev.Automation.StorageEmulator . This package will take care of running the storage emulator in our tests as if we would do when running the Azure functions locally. Inside the StartLocalRuntime method in TestsInitializer class we use it to run the storage emulator. Also note that we have implemented some utility classes in our test project so that we can verify the BLOB creations and to perform clean up operations once the tests are complete.

Now implement the tests. As you can see below, we can use a mix of mocks, actual services when testing the functionalities.

Check how the Azure function is called inside the WhenTheEndpointIsCalled method. In there we can use the registered dependencies and also can pass a mock for the logger as shown below.

Full source code for this project can be found in here

Thanks!

--

--