You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PactNet契约测试中本地托管Azure Function App(提供者)

进程内Azure Function App(v3)结合PactNet做提供者契约测试的启动方案

针对进程内v3函数应用无Program.cs的情况,有两种可行的方式从测试项目启动并完成契约验证:

方案一:在测试项目中手动构建Generic Host启动函数

进程内Azure Function本质基于.NET Generic Host,即使没有Program.cs,也可以在测试代码里直接构建主机并注入模拟依赖:

  1. 在测试项目中引用函数应用的项目,以及必要的NuGet包:Microsoft.Azure.Functions.Worker、Microsoft.Azure.Functions.Worker.Extensions.Http、Microsoft.Extensions.Hosting等。
  2. 编写测试Fixture类,构建主机时指定函数应用的内容根,同时替换需要模拟的依赖:
public class FunctionProviderFixture : IDisposable
{
    private readonly IHost _host;
    public HttpClient Client { get; }

    public FunctionProviderFixture()
    {
        var hostBuilder = new HostBuilder()
            // 指定函数应用的项目目录作为内容根
            .UseContentRoot(Path.Combine(Directory.GetCurrentDirectory(), "../../../YourFunctionAppProject"))
            // 添加函数工作者服务
            .ConfigureFunctionsWorkerDefaults()
            // 替换依赖服务,比如模拟第三方服务或授权组件
            .ConfigureServices(services =>
            {
                // 移除原有的第三方服务注册,替换为模拟实现
                services.RemoveAll<IThirdPartyService>();
                services.AddSingleton<IThirdPartyService>(sp =>
                {
                    var mock = new Mock<IThirdPartyService>();
                    mock.Setup(s => s.GetData(It.IsAny<string>()))
                        .ReturnsAsync(new MockData { Id = "test", Value = "mocked" });
                    return mock.Object;
                });

                // 替换授权服务,比如禁用或模拟认证
                services.RemoveAll<IAuthorizationService>();
                services.AddSingleton<IAuthorizationService>(sp =>
                {
                    var mock = new Mock<IAuthorizationService>();
                    mock.Setup(s => s.ValidateToken(It.IsAny<string>()))
                        .ReturnsAsync(true);
                    return mock.Object;
                });
            });

        _host = hostBuilder.Build();
        _host.StartAsync().Wait();

        // 创建HttpClient用于调用函数
        var factory = _host.Services.GetRequiredService<IHttpClientFactory>();
        Client = factory.CreateClient();
        Client.BaseAddress = new Uri("http://localhost:7071/");
    }

    public void Dispose()
    {
        _host.StopAsync().Wait();
        _host.Dispose();
        Client.Dispose();
    }
}
  1. 在PactNet的提供者测试中使用这个Fixture,直接通过Client调用函数接口验证契约。

方案二:通过Azure Functions Core Tools启动独立进程

如果手动构建主机遇到配置问题,可以用Core Tools启动函数应用进程,同时通过环境变量或测试配置注入模拟依赖:

  1. 在测试项目中添加代码,调用func start命令启动函数应用:
public class FunctionProcessFixture : IDisposable
{
    private readonly Process _funcProcess;
    public HttpClient Client { get; }

    public FunctionProcessFixture()
    {
        // 设置函数应用的工作目录
        var funcProjectPath = Path.Combine(Directory.GetCurrentDirectory(), "../../../YourFunctionAppProject");
        
        // 启动Core Tools进程
        _funcProcess = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "func",
                Arguments = "start",
                WorkingDirectory = funcProjectPath,
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true
            }
        };

        // 设置环境变量,用于在函数应用中切换到测试依赖
        _funcProcess.StartInfo.EnvironmentVariables["ASPNETCORE_ENVIRONMENT"] = "Test";
        _funcProcess.StartInfo.EnvironmentVariables["ThirdPartyService__MockMode"] = "true";

        _funcProcess.Start();

        // 等待函数启动完成(可以通过读取输出日志判断)
        Thread.Sleep(5000);

        Client = new HttpClient { BaseAddress = new Uri("http://localhost:7071/") };
    }

    public void Dispose()
    {
        _funcProcess.Kill();
        _funcProcess.Dispose();
        Client.Dispose();
    }
}
  1. 在函数应用的FunctionsStartup类中,根据环境变量判断是否使用模拟依赖:
public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        var config = builder.GetContext().Configuration;
        var isTestMode = config.GetValue<bool>("ThirdPartyService__MockMode");

        if (isTestMode)
        {
            builder.Services.AddSingleton<IThirdPartyService, MockThirdPartyService>();
            builder.Services.AddSingleton<IAuthorizationService, MockAuthorizationService>();
        }
        else
        {
            builder.Services.AddSingleton<IThirdPartyService, RealThirdPartyService>();
            builder.Services.AddSingleton<IAuthorizationService, RealAuthorizationService>();
        }
    }
}

注意事项

  • 确保测试项目能访问到函数应用的配置文件(如local.settings.json),或者在构建主机时手动加载配置。
  • 模拟授权时,可以直接跳过认证逻辑,或者生成测试用的JWT令牌供Pact测试调用。
  • 使用Core Tools方案时,需要确保本地已安装Azure Functions Core Tools,且版本兼容v3函数。

内容的提问来源于stack exchange,提问作者TanyaMy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 10:20:29