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

Moq触发Func<T1, Task>类型事件时参数不匹配问题求助

解决Moq模拟Func类型事件触发时的参数不匹配异常

问题核心

第三方MqttClient的ConnectedAsync事件是Func<MqttClientConnectedEventArgs, Task>类型(带返回值的委托事件),自定义MyClient监听该事件更新IsConnected属性。用Moq模拟IMqttClient触发事件时,抛出System.Reflection.TargetParameterCountException: Parameter count mismatch.错误。

错误原因

Moq的默认Raise方法是为传统EventHandler<T>(无返回值,接收sender和args两个参数)设计的。而Func<MqttClientConnectedEventArgs, Task>是仅接收args一个参数且返回Task的委托,直接用传统Raise写法会导致参数数量不匹配。

解决方案

以下是两种可靠的测试实现方式,假设你的基础代码如下:

基础代码参考

// IMqttClient接口定义
public interface IMqttClient
{
    event Func<MqttClientConnectedEventArgs, Task> ConnectedAsync;
    // 其他接口成员...
}

// 自定义MyClient类
public class MyClient
{
    private readonly IMqttClient _mqttClient;
    public bool IsConnected { get; private set; }

    public MyClient(IMqttClient mqttClient)
    {
        _mqttClient = mqttClient;
        _mqttClient.ConnectedAsync += OnConnectedAsync;
    }

    private Task OnConnectedAsync(MqttClientConnectedEventArgs args)
    {
        IsConnected = true;
        return Task.CompletedTask;
    }
}

// 事件参数类
public class MqttClientConnectedEventArgs : EventArgs { }

方式1:捕获事件委托并手动调用

通过SetupAdd捕获MyClient注册的事件处理委托,然后手动触发:

[Test]
public async Task ConnectedAsyncEvent_Triggers_IsConnected_True()
{
    // 准备
    var mockMqttClient = new Mock<IMqttClient>();
    var myClient = new MyClient(mockMqttClient.Object);
    Func<MqttClientConnectedEventArgs, Task> connectedHandler = null;

    // 捕获事件处理委托
    mockMqttClient.SetupAdd(m => m.ConnectedAsync += It.IsAny<Func<MqttClientConnectedEventArgs, Task>>())
                  .Callback<Func<MqttClientConnectedEventArgs, Task>>(handler => connectedHandler = handler);

    // 触发事件
    var args = new MqttClientConnectedEventArgs();
    await connectedHandler.Invoke(args);

    // 验证
    Assert.That(myClient.IsConnected, Is.True);
}

方式2:直接调用Mock对象的事件委托

如果不需要验证事件注册逻辑,可直接获取Mock对象的事件委托并触发:

[Test]
public async Task ConnectedAsyncEvent_Triggers_IsConnected_True()
{
    // 准备
    var mockMqttClient = new Mock<IMqttClient>();
    var myClient = new MyClient(mockMqttClient.Object);
    var args = new MqttClientConnectedEventArgs();

    // 直接触发事件委托
    await mockMqttClient.Object.ConnectedAsync?.Invoke(args);

    // 验证
    Assert.That(myClient.IsConnected, Is.True);
}

避坑提醒

  • 不要使用mockMqttClient.Raise(m => m.ConnectedAsync += null, new MqttClientConnectedEventArgs());这种写法,这是为EventHandler<T>设计的,会导致参数计数不匹配。
  • 异步测试中务必用await处理事件委托的返回Task,避免同步阻塞导致的测试不稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 01:12:41