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

如何使用ClientWebSocket连接WebApplicationFactory测试主机

问题描述

我正在按如下方式搭建用于集成测试的测试服务器,该实现目前对所有HttpClient请求均可正常工作:

Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "IntegrationTesting");
var appBuilder = new WebApplicationFactory<Program>()
    .WithWebHostBuilder(builder =>
    {
        builder.ConfigureTestServices(services =>
        {
            services.AddScoped(sp => MockUserMessagingService.Object);
            services.AddSingleton(sp => MockDealerStrategy.Object);
        });
        builder.UseSetting("https_port", "8080");
    });

HttpClient = appBuilder.CreateClient();

现在需要将ClientWebSocket连接到该测试服务器,具体实现方案如下:


实现方案

根据测试场景不同,有两种可选实现方式:

方案一:使用TestServer内置WebSocket客户端(推荐)

WebApplicationFactory底层的TestServer原生支持WebSocket内存转发,不需要监听真实网络端口,和现有HttpClient的内存调用逻辑完全一致,测试执行效率更高,也不会有端口冲突问题,是集成测试的首选方案。
不需要修改现有WebApplicationFactory的配置,直接通过TestServer实例创建WebSocket客户端即可:

// 保留原有appBuilder初始化逻辑不变
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "IntegrationTesting");
var appBuilder = new WebApplicationFactory<Program>()
    .WithWebHostBuilder(builder =>
    {
        builder.ConfigureTestServices(services =>
        {
            services.AddScoped(sp => MockUserMessagingService.Object);
            services.AddSingleton(sp => MockDealerStrategy.Object);
        });
        builder.UseSetting("https_port", "8080");
    });

// 原有HttpClient初始化逻辑不变
HttpClient = appBuilder.CreateClient();

// 创建TestServer内置的WebSocket客户端
var wsClient = appBuilder.Server.CreateWebSocketClient();
// 按需配置请求,比如添加认证头、自定义请求参数
wsClient.ConfigureRequest = req =>
{
    // 示例:添加JWT认证头
    // req.Headers.Add("Authorization", $"Bearer {testToken}");
};
// 直接传入WebSocket端点的相对路径即可建立连接
var webSocket = await wsClient.ConnectAsync(
    new Uri("/你的WebSocket接口路径", UriKind.Relative), 
    CancellationToken.None
);

连接建立后,就可以像使用普通ClientWebSocket一样,调用SendAsync/ReceiveAsync方法和服务端通信。

方案二:使用标准ClientWebSocket连接(适配需要真实网络栈的场景)

如果有特殊测试需求必须用标准ClientWebSocket走真实网络连接,就需要让测试服务启动Kestrel监听真实端口,再拿到监听地址建立连接:

  1. 修改WebApplicationFactory配置,启用Kestrel监听本地空闲端口
  2. 启动测试主机后获取实际监听地址
  3. 初始化ClientWebSocket拼接wss/ws地址建立连接

示例代码:

Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "IntegrationTesting");
var appBuilder = new WebApplicationFactory<Program>()
    .WithWebHostBuilder(builder =>
    {
        builder.ConfigureTestServices(services =>
        {
            services.AddScoped(sp => MockUserMessagingService.Object);
            services.AddSingleton(sp => MockDealerStrategy.Object);
        });
        // 启用Kestrel,监听本地随机空闲端口,避免端口冲突
        builder.UseKestrel(options =>
        {
            options.ListenLocalhost(0, listenOpt =>
            {
                // 如果用wss协议就开启HTTPS,纯ws可以注释掉这行
                listenOpt.UseHttps();
            });
        });
    });

// 启动测试主机
await appBuilder.StartAsync();
// 原有HttpClient初始化逻辑不变
HttpClient = appBuilder.CreateClient();

// 获取Kestrel实际监听的地址
var serverAddr = appBuilder.Server
    .Features
    .Get<Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature>()
    .Addresses
    .First();

// 拼接WebSocket地址:http替换为ws,https替换为wss
var wsAddr = serverAddr
    .Replace("http://", "ws://")
    .Replace("https://", "wss://") 
    + "/你的WebSocket接口路径";

var wsClient = new ClientWebSocket();
// *仅测试场景使用*:忽略本地开发证书校验
wsClient.Options.RemoteCertificateValidationCallback = 
    (_, _, _, _) => true;
// 建立连接
await wsClient.ConnectAsync(new Uri(wsAddr), CancellationToken.None);

注意事项

  • 集成测试不要写死固定端口(比如原配置的8080),用ListenLocalhost(0)让系统分配空闲端口,避免并行测试时端口占用
  • 测试执行完成后记得调用await appBuilder.DisposeAsync()释放测试主机资源,避免进程残留
  • 方案一的内存WebSocket客户端不会走真实网络过滤、SSL校验流程,如果需要测试这部分逻辑,再选择方案二

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:18:25