C# Mock对象方法 C#如何使用Moq创建模拟对象

来源:这里教程网 时间:2026-02-21 17:42:54 作者:

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);

但更实用的是按参数匹配或返回动态值:

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 的粒度。

相关推荐

热文推荐