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

单元测试:如何验证返回Mock的工厂函数的实例化与方法调用

依赖Func<IFoo>工厂的SUT单元测试验证指南

问题背景

被测系统(SUT)依赖两个注入参数:Func<IFoo>委托工厂与IBar接口。SUT内部会通过该工厂实例化IFoo对象,随后分别调用该IFoo对象的方法与持有的_bar对象的方法。
SUT实现代码如下:

public class Sut : ISut
{
    readonly Func<IFoo> _fooFactory;
    IBar _bar;
    
    public Sut(Func<IFoo> fooFactory, IBar bar)
    {
        _fooFactory = fooFactory;
        _bar = bar;
    }
    
    public SutMethod()
    {
        foo = _fooFactory();
        foo.fooMethod();
        
        _bar.barMethod();
    }
}

现有测试的缺陷

目前测试中仅能通过IBar的Mock对象barMock验证_bar的方法调用逻辑,无法直接验证工厂生成的foo对象的状态,需要覆盖两个核心验证点:

  • 工厂被正确调用生成IFoo实例
  • 该IFoo对象的fooMethod方法被正确调用

除了原测试代码中存在的语法笔误外,最核心的逻辑问题是将IFoo的Mock实例完全封闭在工厂委托的闭包内部,外部测试上下文无法获取该Mock实例的引用,自然没有办法在SUT执行完成后,通过Mock对象的Verify方法断言fooMethod的调用行为。
原有测试代码片段:

public class Test
{
    Func<Func<IFoo>, IBar, ISut> _sutFactory;
    
    public Test(Func<Func<IFoo>, IBar, ISut> sutFactory)
    {
        _sutFactory = sutFactory;
    }

    [Fact]
    public void TestCase()
    {
    
        Func<IFoo> fooFactory = () =>
        {
            var mock => new Mock<IFoo>();
            mock.Setup(x => x.fooMethod();
            return mock.Object;
        }   

        Mock<IBar> barMock = new Mock<IBar>();
        
        sut = _sutFactory(fooFactory, barMock);
        sut.SutMethod();
        
        barMock.Verify(mock => mock.barMethod(), Times.Once());
    }   
}

修正后的测试实现

将IFoo的Mock实例提前提到工厂定义的外部,让测试上下文持有该Mock的引用,工厂委托直接返回这个Mock实例即可完成验证。
修正后的测试代码:

public class SutTests
{
    private readonly Func<Func<IFoo>, IBar, ISut> _sutFactory;
    
    public SutTests(Func<Func<IFoo>, IBar, ISut> sutFactory)
    {
        _sutFactory = sutFactory;
    }

    [Fact]
    public void SutMethod_WhenExecuted_ShouldTriggerExpectedMethodCalls()
    {
        // 测试上下文持有IFoo Mock的引用
        var fooMock = new Mock<IFoo>();
        // 工厂委托直接返回可被外部引用的Mock实例
        Func<IFoo> fooFactory = () => fooMock.Object;

        var barMock = new Mock<IBar>();
        
        var sut = _sutFactory(fooFactory, barMock);
        sut.SutMethod();
        
        // 验证IBar方法调用
        barMock.Verify(mock => mock.barMethod(), Times.Once());
        // 验证IFoo方法调用
        fooMock.Verify(mock => mock.fooMethod(), Times.Once());
    }   
}

可选补充验证

如果需要严格确认工厂的调用次数,可以在工厂委托内部增加计数逻辑:

int factoryInvocationCount = 0;
Func<IFoo> fooFactory = () =>
{
    factoryInvocationCount++;
    return fooMock.Object;
};

// SUT方法执行完成后做断言
Assert.Equal(1, factoryInvocationCount);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 20:45:03