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

如何使用NSubstitute模拟Func<ClientWebSocket>?附xUnit测试场景

使用NSubstitute处理Func的模拟需求

你要的方案分两种场景,直接看代码和说明:


场景1:仅需返回真实ClientWebSocket实例

这种情况其实不需要NSubstitute,直接定义委托即可满足需求:

var factory = new Func<ClientWebSocket>(() => new ClientWebSocket());

如果非要贴合NSubstitute的使用习惯,其实没必要——因为Func<ClientWebSocket>是委托类型,本身不需要模拟,直接写逻辑更简单。


场景2:返回模拟的ClientWebSocket实例(推荐用于隔离测试)

如果要避免真实WebSocket对象的副作用(比如资源占用、网络依赖),或者需要验证委托的调用逻辑,用NSubstitute创建ClientWebSocket的替身,再让委托返回它:

修改后的完整测试代码

using NSubstitute;
using Xunit;
using FluentAssertions;

public sealed class WebSocketOptions
{
    public Func<ClientWebSocket> ClientFactory { get; set; } = () => new ClientWebSocket();
    public int MaxMessageSize { get; set; } = 8192;
}

// 补充原代码缺失的Builder实现
public class WebSocketOptionsBuilder
{
    private Func<ClientWebSocket> _clientFactory = () => new ClientWebSocket();
    private int _maxMessageSize = 8192;

    public WebSocketOptionsBuilder WithClientFactory(Func<ClientWebSocket> clientFactory)
    {
        _clientFactory = clientFactory;
        return this;
    }

    public WebSocketOptionsBuilder WithMaxMessageSize(int maxMessageSize)
    {
        _maxMessageSize = maxMessageSize;
        return this;
    }

    public WebSocketOptions Build()
    {
        return new WebSocketOptions
        {
            ClientFactory = _clientFactory,
            MaxMessageSize = _maxMessageSize
        };
    }
}

[Fact]
public void Build_ShouldReturnOptions_WhenAllParametersAreSet()
{
    // Arrange
    // 用NSubstitute创建ClientWebSocket的模拟实例
    var mockWebSocket = Substitute.For<ClientWebSocket>();
    // 定义返回模拟实例的委托
    var factory = new Func<ClientWebSocket>(() => mockWebSocket);
    const int maxMessageSize = 16384;

    var sut = new WebSocketOptionsBuilder();
    var expected = new
    {
        ClientFactory = factory,
        MaxMessageSize = maxMessageSize
    };

    // Act
    var actual = sut
        .WithClientFactory(factory)
        .WithMaxMessageSize(maxMessageSize)
        .Build();

    // Assert
    actual.Should().BeEquivalentTo(expected);
    // 额外验证:委托确实返回了我们的模拟实例
    actual.ClientFactory().Should().Be(mockWebSocket);
}

关键说明

  • 我们模拟的是ClientWebSocket实例,而非Func<ClientWebSocket>委托本身——委托只是传递实例的载体
  • 你提到无需对ClientFactory实现100%覆盖率,所以不需要额外测试委托内部的创建逻辑,只要验证Builder正确传递了委托即可
  • 模拟实例可用于后续验证WebSocket的方法调用(比如ConnectAsync是否被触发)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 14:10:45