如何使用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
相关产品推荐
相关产品推荐

