moq 是 c# 中主流的单元测试 mocking 框架,用于隔离被测代码、控制依赖行为并验证交互;仅限测试项目使用,需 mock 接口或 virtual 成员,通过 setup/returns 配置响应,verify 断言调用次数与参数。

Moq 是什么,什么时候该用它
Moq 是 C# 中最主流的 mocking 框架,专为单元测试设计,用来替代真实依赖(比如 IDataService、IRepository<t></t>)——不是为了“绕过逻辑”,而是为了**隔离被测代码,控制输入与行为,验证交互是否符合预期**。它只在测试项目中使用,生产代码里不该出现 Mock<t></t>。
安装 Moq 并创建基础 Mock 对象
先通过 NuGet 安装:Moq 包(当前稳定版支持 .NET 5+ 和 .NET Standard 2.0+)。安装后,用 Mock<t></t> 构造器创建模拟实例:
var mockLogger = new Mock<ILogger>();
注意:T 必须是接口或带 virtual 成员的类(Moq 无法 mock sealed 类或非 virtual 方法)。如果你 mock 一个类,且该类有无参构造函数,Moq 会调用它;否则需显式传入构造参数。
- 接口 mock 最安全,推荐优先使用
- mock 类时,所有非 virtual 成员仍走原实现,容易误判行为
- 别对
static或internal成员设期望——Moq 无法拦截它们
设置方法返回值和行为(Setup / Returns)
用 Setup() 声明某个方法被调用时的响应。最常见的是 Returns():
mockLogger.Setup(x => x.Log("Error occurred")).Returns(true);但更实用的是按参数匹配或返回动态值:
本文档主要讲述的是maven使用方法;Maven是基于项目对象模型的(pom),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具。Maven将你的注意力从昨夜基层转移到项目管理层。Maven项目已经能够知道 如何构建和捆绑代码,运行测试,生成文档并宿主项目网页。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
- 用
It.IsAny<string>()</string>匹配任意字符串参数:Setup(x => x.Log(It.IsAny<string>())).Returns(true)</string> - 用
Returns((string msg) => $"[LOG]{msg}")实现委托返回,可做简单转换 - 用
Throws<argumentexception>()</argumentexception>模拟异常场景 -
SetupSequence()可定义多次调用的不同返回值(如第一次成功、第二次失败)
⚠️ 常见错误:写成 Setup(x => x.Log("Error occurred")).Returns(true),但实际调用是 Log("error occurred")(大小写不同)——匹配失败,返回默认值(false 或 null),测试看似通过实则没覆盖逻辑。
验证方法是否被调用(Verify)
仅设期望不够,还要确认被测代码确实按约定调用了依赖。用 Verify() 断言:
mockLogger.Verify(x => x.Log(It.IsAny<string>()), Times.Once());
关键点:
-
Times.Once()、Times.AtLeastOnce()、Times.Exactly(2)等控制调用频次 - 不带参数的
Verify()会检查所有已Setup的成员是否被调用(慎用,易导致过度断言) - 如果方法被调用但参数不匹配(比如期望
"User not found",实际传了"user not found"),Verify会失败并抛出Moq.MockException - 异步方法要 mock
Task返回值,并用Verify()配合Times,不能只靠 await 后断言结果
真正难的不是写 Setup,而是想清楚:这个依赖在当前测试场景下,应该被调用几次?传什么参数?有没有边界条件(null、空字符串、超长文本)需要覆盖?这些决定了 Setup 和 Verify 的粒度。









