首页 > 解决方案 > 如何为使用包装器的 Azure Functions 编写单元测试?

问题描述

我在所有 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
        }
    }
}

以下是它在函数中的使用方式:

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);
        });
    }
}

我正在尝试为此 GetPost 函数编写单元测试。在这种情况下如何模拟 FunctionWrapper 类?

标签: c#unit-testing.net-coredependency-injectionazure-functions

解决方案


模拟包装抽象的期望行为。

以下示例使用 MOQ 来模拟包装器。注意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
    }
}

原始问题中的代码省略了被测对象的大部分正文。话虽如此,这个例子是基于最初提供的,它被用来创建一个可重现的例子,用于创建上面的测试


推荐阅读