使用Moq模拟IRepo时为何返回未映射的Address1属性?
问题原因与修复方案
问题根源
你当前的测试完全没有调用真实的Repo类逻辑,而是用Moq创建了IRepo的模拟对象。你在Setup中明确指定Execute方法返回自己手动创建的expectedResult——这个对象里你主动给Address1赋了值,所以模拟对象必然返回包含该属性值的实例,和真实Repo中“不映射Address1”的逻辑没有任何关联。
简单来说:你测试的是Moq的模拟行为,而非真实Repo的业务逻辑。
修复方案
方案1:测试真实Repo的映射逻辑(需隔离数据库)
要验证真实Repo中“仅映射ID和Name,Address1保持默认值”的逻辑,需要先把数据库操作抽象为独立接口,再用Moq模拟数据库返回的数据,让真实Repo依赖模拟的数据库接口,从而在不连接真实数据库的情况下测试Repo的映射逻辑。
步骤如下:
- 抽象数据库访问接口:
public interface IDbAccess { (int Id, string Name) GetModelData(DateTime date); }
- 修改Repo依赖该接口:
public class Repo : IRepo { private readonly IDbAccess _dbAccess; public Repo(IDbAccess dbAccess) { _dbAccess = dbAccess; } public Model Execute(DateTime date) { var dbData = _dbAccess.GetModelData(date); return new Model() { ID = dbData.Id, Name = dbData.Name // 不设置Address1,保持默认值null }; } }
- 编写单元测试:
[Test] public void Repo_Execute_OnlyMapsIdAndName() { // 模拟数据库返回的数据 var mockDbAccess = new Mock<IDbAccess>(); mockDbAccess.Setup(d => d.GetModelData(It.IsAny<DateTime>())) .Returns((1, "Username")); // 实例化真实Repo,注入模拟的数据库访问组件 var repo = new Repo(mockDbAccess.Object); var result = repo.Execute(DateTime.Now); // 验证映射结果 Assert.AreEqual(1, result.ID); Assert.AreEqual("Username", result.Name); Assert.IsNull(result.Address1); // 验证Address1未被赋值 }
方案2:明确测试目标(若无需测试真实Repo)
如果你的场景不需要测试真实Repo,只是想验证依赖IRepo的其他组件逻辑,但你当前没有服务类,那这种测试其实没有实际业务价值——它只是在验证Moq的设置是否正确。此时你应该重新明确测试目标:单元测试的核心是验证真实业务逻辑,而非模拟框架的行为。
内容的提问来源于stack exchange,提问作者HarshSharma
相关产品推荐
相关产品推荐

