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

如何让Mock在Setup未精确匹配时返回null?默认设置无效求解决

问题

我在测试时希望Moq在未匹配到Setup的调用时返回null,但目前它总是返回带默认值的Mock对象。尝试过mock.SetReturnsDefault(null)和mock.DefaultValue = null都没效果。

测试代码如下:

[Theory]
[InlineData("DFF0DF04-0D3F-419B-82FB-23F0A8E2452C", 1)]
[InlineData("DFF0DF04-0D3F-419B-82FB-23F0A8E2452C", 2)]
[InlineData("985F7161-1B0F-4EEA-9572-02D6D13D712B", 1)]
public async Task Get_ShouldReturn1TierSet_GivenAProgram_And_AnExistingId(Guid programId, int id)
{
    _tierSetService.Setup(x => x.GetTierSet(1, new Guid("DFF0DF04-0D3F-419B-82FB-23F0A8E2452C"))).ReturnsAsync(new TierSet()
    {
        Id = 1,
        StartDate = DateTime.Now,
        EndDate = DateTime.Now,
        Name = "Some Tier Set",
        TierSetState = Core.Constants.TierSetState.Draft,
        CreateDate = DateTime.Now,
        Program = new Domain.Models.Program(){ },
        DisplayTierSet = false
    });

    var actual = await _controller.Get(programId, id);
    if (programId == new Guid("DFF0DF04-0D3F-419B-82FB-23F0A8E2452C") && id == 1)
    {
        Assert.NotNull(actual);
    }
    else
    {
        Assert.Null(actual);
    }
}

另外,我单独加了一个测试,用It.IsAny<>参数设置Mock返回null是正常工作的,但为什么默认设置就无效?怎么才能确保未匹配Setup时返回null?


原因分析

Moq的DefaultValue和SetReturnsDefault仅对完全没有Setup的成员生效。如果你已经对某个方法(比如GetTierSet)设置了至少一个匹配规则,那么所有对该方法的调用都会优先尝试匹配已有的Setup——如果没有匹配上,Moq会自动生成该方法返回类型的默认实例(引用类型是空Mock对象,值类型是默认值),而不会触发全局的默认返回设置。

你用It.IsAny<>设置返回null能生效,是因为这个Setup覆盖了所有对GetTierSet的调用,相当于一个“兜底”的匹配规则,而不是依赖全局默认值。


解决方案

要实现“精确匹配的Setup返回指定值,其他调用返回null”,有两种可靠方式:

  1. 添加兜底的Setup规则
    在你的精确匹配Setup之后,添加一个覆盖所有参数的Setup,明确返回null:

    // 精确匹配的Setup
    _tierSetService.Setup(x => x.GetTierSet(1, new Guid("DFF0DF04-0D3F-419B-82FB-23F0A8E2452C")))
                   .ReturnsAsync(new TierSet() { /* ... */ });
    
    // 兜底规则:所有其他调用返回null
    _tierSetService.Setup(x => x.GetTierSet(It.IsAny<int>(), It.IsAny<Guid>()))
                   .ReturnsAsync((TierSet)null);
    

    Moq会按照Setup的定义顺序匹配,先尝试精确匹配,匹配失败就会触发这个兜底规则。

  2. 使用DefaultValueProvider自定义默认行为(针对Moq 4.13+)
    如果需要全局生效,可以自定义默认值提供器,让未匹配的方法调用返回null:

    var mock = new Mock<ITierSetService> { DefaultValueProvider = new NullDefaultValueProvider() };
    
    // 自定义提供器实现
    public class NullDefaultValueProvider : DefaultValueProvider
    {
        protected override object GetDefaultValue(Type type, Mock mock)
        {
            return type.IsValueType ? base.GetDefaultValue(type, mock) : null;
        }
    }
    

    这种方式适合需要对多个Mock统一设置默认返回null的场景,但注意:如果某个方法已经有至少一个Setup,依然会优先走Setup的匹配逻辑,只有完全没有Setup的方法才会用这个默认值。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 03:05:29