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
相关产品推荐
相关产品推荐

