测试 .NET 7 独立辅助角色 Azure 函数

Testing a .NET 7 isolated worker azure function

提问人:James 提问时间:11/17/2023 更新时间:11/17/2023 访问量:75

问:

我创建了一个包含一些中间件的 .NET 7 独立工作器函数。现在,我希望自托管此函数,以便能够创建一个测试,该测试检查函数及其关联的中间件是否按预期执行(通过在单个测试中运行该函数及其相应的中间件)。有没有人有关于实现这一目标的指导?

internal sealed class StampHttpHeaderMiddleware : IFunctionsWorkerMiddleware
{
    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
        // implementation
    }
}
c# asp.net-mvc azure-functions

评论


答:

0赞 SiddheshDesai 11/17/2023 #1

您可以直接在现有函数解决方案中创建一个 XUnit 或任何测试项目,并添加以下代码:-

我的功能解决方案与测试项目:-

代码1:-

我的单元测试.cs:-

using System.Net;
using FunctionApp63;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;

namespace FunctionApp63.Tests
{
    public class Function1Tests
    {
        [Fact]
        public void Run_Returns_Welcome_Message()
        {
            // Arrange
            var loggerFactoryMock = new Mock<ILoggerFactory>();
            var loggerMock = new Mock<ILogger>();

            loggerFactoryMock.Setup(x => x.CreateLogger(It.IsAny<string>())).Returns(loggerMock.Object);

            var requestMock = new Mock<HttpRequestData>();
            var responseMock = new Mock<HttpResponseData>();

            // Simulate the function call
            var function = new Function1(loggerFactoryMock.Object);
            var response = function.Run(requestMock.Object);

            // Assert
            Assert.NotNull(response);
            Assert.Equal(HttpStatusCode.OK, response.StatusCode);

            // Verify that the response contains the expected content type
            Assert.True(response.Headers.TryGetValues("Content-Type", out var contentTypes));
            Assert.Contains("text/plain; charset=utf-8", contentTypes);
        }
    }
}

输出:-*

enter image description here

代码2:-

我的单元测试.cs:-

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;

namespace FunctionApp63.Tests
{
    public class Function1IntegrationTests
    {
        private const string FunctionBaseUrl = "http://localhost:7083"; // Replace with your function host URL

        [Fact]
        public async Task Run_Returns_Welcome_Message()
        {
            // Arrange
            using var client = new HttpClient();

            // Act
            var response = await client.GetAsync(new Uri($"{FunctionBaseUrl}/api/Function1"));

            // Assert
            Assert.NotNull(response);
            Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);

            var content = await response.Content.ReadAsStringAsync();
            Assert.Contains("Welcome to Azure Functions!", content);
        }
    }
}

输出:-

enter image description here

使用中间件:-

我已经使用我的 .Net 7.0 隔离 Http 触发器实现了自定义中间件,并为两者执行了如下测试:-

创建了一个名为中间件的文件夹,并在其中添加了LoggingMiddleware.cs,如下所示:-

using Microsoft.Extensions.Logging;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Middleware;

namespace FunctionApp62
{
    public class LoggingMiddleware : IFunctionsWorkerMiddleware

    {
        private readonly ILogger _logger;

        public LoggingMiddleware(ILogger<LoggingMiddleware> logger)
        {
            _logger = logger;
        }

        public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
        {
            _logger.LogInformation("Middleware executing before function.");

            await next(context);

            _logger.LogInformation("Middleware executing after function.");
        }
    }
}

使用以下代码创建一个测试文件夹并添加了 Function1Tests.cs 文件:-

using System.Net;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;

namespace FunctionApp62.Tests
{
    public class Function1Tests
    {
        [Fact]
        public Task TestFunction()
        {
            var logger = new Mock<ILogger>();
            var loggerFactory = new Mock<ILoggerFactory>();
            loggerFactory.Setup(factory => factory.CreateLogger(It.IsAny<string>())).Returns(logger.Object);

            var httpRequestData = new Mock<HttpRequestData>();
            return Task.CompletedTask;
        }
    }
}

我的程序.cs,包括中间件:-

using FunctionApp62;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(services =>
    {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
        services.AddSingleton<LoggingMiddleware>();
    })
    .Build();

host.Run();

我的函数1与中间件.cs:-

using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using System.Net;

namespace FunctionApp62
{
    public class Function1
    {
        private readonly ILogger _logger;
        private readonly LoggingMiddleware _loggingMiddleware;

        public Function1(ILoggerFactory loggerFactory, LoggingMiddleware loggingMiddleware)
        {
            _logger = loggerFactory.CreateLogger<Function1>();
            _loggingMiddleware = loggingMiddleware;
        }

        [Function("Function1")]
        public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
        {
            _logger.LogInformation("C# HTTP trigger function processed a request.");

            var response = req.CreateResponse(HttpStatusCode.OK);
            response.Headers.Add("Content-Type", "text/plain; charset=utf-8");

            response.WriteString("Welcome to Azure Functions!");

            return response;
        }
    }
}

您还可以使用中间件在此函数解决方案中添加 Xunit 并执行测试:-

我的解决方案:-

enter image description here

参考:-

azure-functions-tests/csharp-visualstudio 在 master ·Azure-Samples/azure-functions-tests (github.com)