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

如何在被测类(SUT)构造函数中模拟Func<枚举,接口>参数

问题

在我的.Net6 Web应用中,我尝试为单个IWordRepository接口的两个实现注册依赖注入:

  • WordRepositoryInMemory:操作内存数据;
  • WordRepositoryDatabase:调用数据库;

我创建了枚举来标识不同实现:

public enum WordRepositoryImplementation
{
    WordRepositoryInMemory,
    WordRepositoryDatabase
}

随后在Program.cs中注册两个服务及对应的解析委托:

builder.Services.AddScoped<WordRepositoryDatabase>();
builder.Services.AddScoped<WordRepositoryInMemory>();

builder.Services.AddTransient<Func<WordRepositoryImplementation, IWordRepository?>>(wordRepositoryProvider => key =>
{
    return key switch
    {
        WordRepositoryImplementation.WordRepositoryInMemory => wordRepositoryProvider.GetService<WordRepositoryInMemory>(),
        WordRepositoryImplementation.WordRepositoryDatabase => wordRepositoryProvider.GetService<WordRepositoryDatabase>(),
        _ => null,
    };
});

控制器通过构造函数接收该委托并获取指定实现:

private readonly IWordRepository _wordRepositoryDatabase; // 此控制器仅需调用其中一个实现

public DictionaryDataController(Func<WordRepositoryImplementation, IWordRepository> serviceResolver)
{
    _wordRepositoryDatabase = serviceResolver(WordRepositoryImplementation.WordRepositoryDatabase);
}

但这种实现导致控制器测试无法通过简单的Mock.Object实例化被测类(SUT)。我尝试设置Func<WordRepositoryImplementation, IWordRepository?>类型的字段来返回Mock对象,但写法有误:

_funcWordRepositoryImplementation= () =>
{
    return new Mock<WordRepositoryImplementation, IWordRepository>();
};

请问该如何正确设置这个字段?

解决方案

你需要创建一个返回Mock对象实例的委托,而不是直接MockFunc本身(或者更简单的是直接定义符合Func<WordRepositoryImplementation, IWordRepository?>签名的委托)。

方法1:直接构造符合签名的委托

先创建IWordRepository的Mock实例,然后定义Lambda表达式,当传入指定枚举值时返回这个Mock对象:

// 先创建数据库实现的Mock
var mockDbRepo = new Mock<IWordRepository>();
// 可在这里配置Mock的行为,比如Setup方法
mockDbRepo.Setup(repo => repo.SomeMethod()).Returns("模拟数据");

// 定义符合签名的Func委托
Func<WordRepositoryImplementation, IWordRepository?> _funcWordRepositoryImplementation = key =>
{
    return key switch
    {
        WordRepositoryImplementation.WordRepositoryDatabase => mockDbRepo.Object,
        // 如果需要内存实现的Mock,可在此添加
        // WordRepositoryImplementation.WordRepositoryInMemory => mockInMemoryRepo.Object,
        _ => null
    };
};

方法2:用Moq直接Mock Func委托(适用于更灵活的场景)

如果你想用Moq来Mock整个Func委托,可以这样写:

var mockFunc = new Mock<Func<WordRepositoryImplementation, IWordRepository?>>();
var mockDbRepo = new Mock<IWordRepository>();

// 设置当传入指定枚举值时,返回Mock的Repo对象
mockFunc.Setup(f => f(WordRepositoryImplementation.WordRepositoryDatabase))
        .Returns(mockDbRepo.Object);

实例化控制器(SUT)的正确方式

不管用哪种方法,最终只需把委托实例传入控制器构造函数即可:

// 用方法1的委托实例化控制器
var controller = new DictionaryDataController(_funcWordRepositoryImplementation);

// 或用方法2的Mock Func实例
var controller = new DictionaryDataController(mockFunc.Object);

这样就能正常实例化被测控制器,同时Mock对象也能按预期工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 18:48:24