How to write unit tests for Azure Functions that use wrapper?

Viewed 1232

I use a wrapper class on all of my Azure Functions:

public interface IFunctionWrapper
{
    Task<IActionResult> Execute(HttpRequest req, ExecutionContext context, Func<Task<IActionResult>> azureFunction);
}

public class FunctionWrapper : IFunctionWrapper
{
    private readonly ILogger _log;

    public FunctionWrapper(ILogger<FunctionWrapper> log)
    {
        _log = log;
    }

    public async Task<IActionResult> Execute(HttpRequest req, ExecutionContext context, Func<Task<IActionResult>> azureFunction)
    {
        try
        {
            // Log few extra information to Application Insights

            // Do authentication

            return await azureFunction();
        }
        catch (Exception ex)
        {    
            // Return a custom error response
        }
    }
}

And here is how it is used in a function:

public class MyFunctions
{
    private readonly IFunctionWrapper _functionWrapper;

    public MyFunctions(IFunctionWrapper functionWrapper)
    {
        _functionWrapper = functionWrapper;
    }

    public async Task<IActionResult> GetPost(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
        ExecutionContext context,
        ILogger log)
    {
        return await _functionWrapper.Execute(req, context, async () =>
        {
            // Function code...
    
            return new JsonResult(post);
        });
    }
}

I am trying to write unit tests for this GetPost function. How can I mock the FunctionWrapper class in this situation?

2 Answers

Mock the desired behavior of the wrapper abstraction.

The following example uses MOQ to mock the wrapper. Pay attention to the setup of the mock

[TestClass]
public class MyFunctionsTests {
    [TestMethod]
    public async Task GetPost_Should_Execute_Wrapper() {
        //Arrange
        //mock the wrapper
        IFunctionWrapper wrapper = Mock.Of<IFunctionWrapper>();
        //configure the mocked wrapper to behave as expected when invoked
        Mock.Get(wrapper)
            .Setup(_ => _.Execute(It.IsAny<HttpRequest>(), It.IsAny<ExecutionContext>(), It.IsAny<Func<Task<IActionResult>>>()))
            .Returns((HttpRequest r, ExecutionContext c, Func<Task<IActionResult>> azureFunction) => 
                azureFunction()); //<-- invokes the delegate and returns its result

        MyFunctions function = new MyFunctions(wrapper);

        //these should be initialized as needed for the test
        HttpRequest req = null; 
        ExecutionContext ctx = null;
        ILogger log = Mock.Of<ILogger>();

        //Act
        IActionResult result = await function.GetPost(req, ctx, log);

        //Assert
        result.Should().NotBeNull();
        //verify that mocked wrapper was called
        Mock.Get(wrapper).Verify(_ => _.Execute(It.IsAny<HttpRequest>(), It.IsAny<ExecutionContext>(), It.IsAny<Func<Task<IActionResult>>>()));

        //...perform other assertions here
    }
}

The code in the original question omitted most of the body of the subject under test. That being said, this example is based on what was originally provided, which was used to create a reproducible example used to create the test above

You don't need to create a wrapper interface at all:

  • HttpRequest is mockable: https://mahmutcanga.com/2019/12/13/unit-testing-httprequest-in-c/
  • ExecutionContext can be mocked (or as its just a POCO used as-is)
  • ILogger can be mocked
  • Use dependency injection to inject the dependencies of the function (and mock those then).
  • Remember you really only want to test that parameter validation and possible parsing works correctly.
Related