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

含可选参数的Mock方法调用方式不同返回结果异常不一致

问题:Moq模拟带可选参数的接口时,不同调用方式返回结果不一致

我Mock了一个带有可选参数的接口方法,预期它返回true,但当仅传入必填参数(使用默认可选参数)和传入所有参数时,得到的结果却不同。以下是完整可复现的示例代码:

using Moq;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Abstractions;
namespace MoqTest
{
    public interface IProcedureService
    {
        Task<bool> InterfaceMethod(string req1, int req2, int? opt1 = null, CancellationToken opt2 = default);
    }
    public class Tests
    {
        Mock<IProcedureService> _procedureService = new Mock<IProcedureService>();
        ITestOutputHelper _output;
        public Tests(ITestOutputHelper output) => _output = output;

        [Xunit.Fact]
        public async void DoTheTest()
        {
            _procedureService.Setup(x => x.InterfaceMethod(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<CancellationToken>()))
                .ReturnsAsync(true);

            _output.WriteLine($"result from IsUniqueProcedureNameInWorkspace (using optional defaults) " +
                $"{(await _procedureService.Object.InterfaceMethod("", 0))}"); // returns false
            _output.WriteLine($"result from IsUniqueProcedureNameInWorkspace (NOT using optional defaults) " +
                $"{(await _procedureService.Object.InterfaceMethod("", 0, 0, default))}"); // returns true
        }
    }
}

执行后输出如下:

Standard Output: 
result from IsUniqueProcedureNameInWorkspace (using optional defaults) False
result from IsUniqueProcedureNameInWorkspace (NOT using optional defaults) True

我原本预期两种调用方式都返回True,因为我在Setup中使用It.IsAny匹配了所有参数。请问我忽略了什么?我的Moq版本为4.20.70。


原因与解决方案

核心原因

Moq的方法匹配严格遵循参数类型匹配规则:你在Setup中用It.IsAny<int>()匹配第三个参数,但接口定义里的opt1是int?(可空int)类型。int和int?是不同的类型,It.IsAny<int>()无法匹配int?类型的参数(即使该参数的值是null)。

当你调用InterfaceMethod("", 0)时,第三个参数传递的是默认值null(int?类型),无法命中当前Setup,所以Moq返回该方法的默认值false;而调用InterfaceMethod("", 0, 0, default)时,第三个参数是int类型的0,会被隐式转换为int?,此时Setup里的It.IsAny<int>()刚好匹配这个隐式转换后的基础类型值,因此命中Setup返回true。

修复方案

将Setup中的It.IsAny<int>()替换为It.IsAny<int?>(),确保参数类型完全匹配:

_procedureService.Setup(x => x.InterfaceMethod(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int?>(), It.IsAny<CancellationToken>()))
    .ReturnsAsync(true);

修改后,两种调用方式都会命中该Setup:

  • 省略可选参数时,opt1是null(int?类型),It.IsAny<int?>()可以匹配;
  • 传入0作为opt1时,0会被隐式转换为int?,同样能被It.IsAny<int?>()匹配。

这样两种调用都会返回预期的true。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:05:54