Unit testing Azure Functions

Photo by Henry Lai on Unsplash

Unit testing Azure Functions

...and some SonarCloud code analysis!

Nicklas Møller Jepsen
·Jun 4, 2022·

4 min read

Subscribe to my newsletter and never miss my upcoming articles

We all want to find these little bugs before they cause too much trouble!

Here's what we will cover

  • How to do a (very)simple Azure Function
  • Add some unit tests (xUnit)
  • Use Moq
  • ...a bit of SonarQube/SonarCloud

When working with Azure Functions in real world scenarios it can sometime be a pain to run them. The reason for this is that with micro services like Azure Functions they almost always exist in a complex setup with lots of different moving parts and you often don't have full control over when they are executed, etc. That's one of the reasons why it's a good idea to write some unit tests when you develop your functions. There are of course a lot of other good reasons for writing unit tests, but you know that already 😎

You can also run your functions locally, which you should also do, here's how to do that

Before we dig in....

xUnit, NUnit, MSTest, what to choose?

It's a personal choice and there's no right answer. I prefer xUnit because you can use [Fact] and inject test data via attributes with [InlineData], [ClassData], and [MemberData].

Let's Get Test Driven

We are going to start writing the unit test for our function, that way we can brag about doing Test Driven Development (and it actually makes pretty good sense as a bonus 😁) Simply launch Visual Studio, create a new unit test project, select your test framework of choice, if you're going to use my samples you need to select xUnit:

image.png

In the new test project add the Moq Nuget:

install-package Moq

In the following code we are going to:

  1. Arrange our test by setting up the mock objects we need
  2. Act by calling our function
  3. Assert by validating the response against what we expect
[Theory]
[InlineData("", typeof(BadRequestResult))]
[InlineData("QueryParamValue", typeof(OkResult))]
[InlineData("ThisStringCausesTheFunctionToThrowAnError", typeof(InternalServerErrorResult))]
public async Task Function_Returns_Correct_StatusCode(string queryParam, Type expectedResult)
{
    //Arrange
    var qc = new QueryCollection(new Dictionary<string, StringValues>{{"q", new StringValues(queryParam)}});
    var request = new Mock<HttpRequest>();
    request.Setup(x => x.Query)
        .Returns(() => qc);

    var logger = Mock.Of<ILogger>();
    //Act
    var response = await Function1.Run(request.Object, logger);
    //Assert
    Assert.True(response.GetType() == expectedResult);
}

When doing TTD we will have compilation errors at this point, obviously because we haven't added the function yet.

The Function

Now add a new Azure Functions project, select Http trigger:

image.png

Replace the code in the class Function1.cs with this:

public static class Function1
{
    [FunctionName("Function1")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");

        string queryParameter = req.Query["q"];
        if (string.IsNullOrEmpty(queryParameter))
            return new BadRequestResult();

        if (queryParameter == "ThisStringCausesTheFunctionToThrowAnError")
            return new InternalServerErrorResult();

        return new OkResult();
    }
}

You will notice that the QueryCollection that we mocked in the unit test are used in the HttpRequest passed to this function. It should be pretty obvious what happens here, we just do simple string comparison to be able to return different Http results that our tests can do assertions on.

Now build you projects and things should compile.

Running the Tests

Remember the [InlineData] attributes we had in our test method? We are using those to parameterize the test so we can have multiple test cases in one test method. When we run our tests in VS, here's how it should look:

image.png

...you will notice one test run per [InlineData] attribute.

That's it for our simple unit test of Azure Functions. I know a lot of people are using Dependency Injection in Azure Functions (my self included) and if that's the case you will have to make some modifications to this, let me know in the comments if you're interested in a blob post about that.

SonarCloud, a little teaser for an upcoming post

I have added this sample project to my sonarcloud.io account since I'm really starting to use that a lot for many project and I really like the features they have and how easy it is to improve code quality with a tool like SonarCloud.

So for this little project, here's how the SonarCloud analysis looks:

image.png

Stay tuned for a post on how to configure GitHub actions to trigger a SonarCloud analysis and get your source code analysed.

That's all, as always you can find the relevant source code on my Github, here's the repo

 
Share this