Moq 是一个轻量易用的 .NET 模拟框架,用于通过接口和虚方法创建假对象以隔离被测代码,提升单元测试的速度、可重复性与可靠性。
Moq 是一个轻量、易用的 .NET 模拟(Mock)框架,专为接口和虚方法设计。它让你在不依赖真实实现的情况下,创建“假对象”来隔离被测代码——比如模拟数据库访问、HTTP 客户端或第三方服务。这样写单元测试时,速度快、可重复、不污染数据,也更容易验证行为逻辑是否正确。
在项目中通过 NuGet 安装 Moq 包:
dotnet add package Moq(.NET CLI)
或在 Visual Studio 中右键项目 → “管理 NuGet 包” → 搜索 Moq → 安装最新稳定版。
确保你的待测类依赖的是接口(如 IService),而不是具体类型。Moq 无法直接 mock 非虚成员或密封类。
假设你有如下接口和待测服务:
// 接口定义public interface IEmailSender { string Send(string to, string body); }
// 被测类public class NotificationService { private readonly IEmailSender _sender; public NotificationService(IEmailSender sender) => _sender = sender; public string Notify(string user) => _sender.Send(user, "Welcome!"); }
用 Moq 编写测试:
var mockSender = new Mock();
mockSender.Setup(x => x.Send("test@example.com", "Welcome!"))
.Returns("OK");
var service = new NotificationService(mockSender.Object);
var result = service.Notify("test@example.com");
Assert.Equal("OK", result);
关键点:
- Mock 创建模拟器
- .Setup() 定义调用规则(参数匹配很重要)
- .Object 获取模拟实例供被测类使用
除了返回值,你还可以检查方法是否被调用、调用了几次、参数是否符合预期:
mock.Setup(x => x.Send(It.IsAny(), It.IsAny())).Returns("OK"); —— 忽略具体参数值mock.Verify(x => x.Send("a@b.com", "Welcome!"), Times.Once()); —— 验证精确调用一次mock.Verify(x => x.Send(It.Is(s => s.Contains("@"))), Times.AtLeastOnce()); —— 自定义参数校验mock.Setup(x => x.Send(It.IsAny(), It.IsAny())).Throws(); —— 模拟异常场景Moq 不是万能的:
- 不能 mock static、sealed 类或非虚(non-virtual)方法
- 属性默认是只读的,要 mock set 访问器需显式声明为 virtual set
- 使用 It.Is 时注意闭包捕获变量,避免测试不稳定
- 过度 mock 可能掩盖设计问题(比如依赖太多、职责不清),优先考虑重构而非硬 mock
基本上就这些。Moq 上手快,但真正写好模拟测试
,核心还是理解“隔离”和“行为驱动”的思路。