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

C#单元测试遇System.NotSupportedException:Mock Setup失败求助

问题描述

运行单元测试时始终抛出System.NotSupportedException异常,问题出在服务Mock的Setup方法上。已知需要进行抽象处理,请问是否需要将一个或多个类声明为abstract或virtual?具体该如何实现?

原代码如下:

public class BaseService
{
    public string GetData(string password)
    {
        string result = "";

        if (password.Equals("password")) 
        {
             result = "granted";
        }

        return result;
    }
}

public class LookupService
{
    private readonly BaseService baseService;

    public LookupService()
    {
        baseService = new BaseService();
    }

    public LookupService(BaseService @base)
    {
        baseService = @base;
    }

    public string GetCode(string password)
    {
        string returnString = baseService.GetData(password);

        return returnString;
    }
}

public class UnitTest_LookupService
{
    LookupService lookupService { get; set; }

    [Fact]
    public void moqTest()
    {
        Mock<BaseService> baseMock = new Mock<BaseService>();

        lookupService = new LookupService(baseMock.Object);

        baseMock.Setup(x => x.GetData("password")).Returns("granted");

        string result = lookupService.GetCode("password");

        Assert.Equal("granted", result);
    }
}
解决方案

Moq框架仅能Mock虚方法(virtual)、抽象方法(abstract)或接口中的方法——它需要通过生成动态代理类覆盖原有逻辑,普通非虚方法无法被代理,这就是抛出异常的核心原因。

有两种可行的解决方式:

方式一:将目标方法改为virtual

直接修改BaseService中的GetData方法,添加virtual关键字,让Moq可以生成代理类覆盖该方法:

public class BaseService
{
    // 添加virtual关键字
    public virtual string GetData(string password)
    {
        string result = "";

        if (password.Equals("password")) 
        {
             result = "granted";
        }

        return result;
    }
}

单元测试代码无需修改,即可正常运行。

方式二:使用接口抽象(更推荐)

遵循依赖倒置原则,面向抽象而非具体实现编程,通过定义接口解耦依赖关系:

1. 定义接口

public interface IBaseService
{
    string GetData(string password);
}

2. 修改BaseService实现接口

public class BaseService : IBaseService
{
    public string GetData(string password)
    {
        string result = "";

        if (password.Equals("password")) 
        {
             result = "granted";
        }

        return result;
    }
}

3. 修改LookupService依赖接口

public class LookupService
{
    private readonly IBaseService _baseService;

    public LookupService()
    {
        _baseService = new BaseService();
    }

    // 构造函数依赖接口而非具体类
    public LookupService(IBaseService baseService)
    {
        _baseService = baseService;
    }

    public string GetCode(string password)
    {
        return _baseService.GetData(password);
    }
}

4. 修改单元测试Mock接口

public class UnitTest_LookupService
{
    LookupService lookupService { get; set; }

    [Fact]
    public void moqTest()
    {
        // Mock接口而非具体类
        Mock<IBaseService> baseMock = new Mock<IBaseService>();

        lookupService = new LookupService(baseMock.Object);

        baseMock.Setup(x => x.GetData("password")).Returns("granted");

        string result = lookupService.GetCode("password");

        Assert.Equal("granted", result);
    }
}

这种方式彻底解耦了LookupService与BaseService的具体实现,后续替换BaseService的实现类时无需修改LookupService代码,更符合开闭原则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 02:05:25