Dapper仓储层单元测试核心是验证SQL逻辑、参数绑定、映射行为及异常路径,需隔离数据库依赖,用内存数据或FakeDbConnection模拟,重点覆盖空集合、null参数、列名映射、复杂类型填充等易错点,不测连接与事务。

写 Dapper 仓储层的单元测试,核心不是去测 Dapper 本身(它已稳定),而是验证你的 SQL 逻辑、参数绑定、映射行为和异常路径是否符合预期。关键在于隔离数据库依赖,用内存数据或模拟对象替代真实数据库连接。
用内存集合 + QueryMultiple 模拟多结果集
Dapper 的 QueryMultiple 常用于一次查多个表(如主从关系)。真实数据库难 mock,但你可以用 SqlMapper.GridReader 的模拟实现,或更简单:把测试数据预先放在 List 中,手动构造类似 QueryMultiple 的返回结构。
- 定义测试用的内存数据(如
new List){ new Order { Id = 1 } } - 用
new GridReaderMock(list1, list2)包装(可自建轻量 mock 类,只需实现Read和() ReadFirst)() - 在仓储方法中,对
IDbConnection做接口抽象(如IConnectionFactory),测试时注入返回 mock reader 的实现
用 FakeDbConnection 替代真实连接
不依赖 EF 或第三方 mock 工具,可手写一个 FakeDbConnection:它不连数据库,只记录执行的 SQL 和参数,并按预设规则返回测试数据。
- 继承
DbConnection,重写CreateCommand()返回FakeDbCommand -
FakeDbCommand的ExecuteReader()不查库,而是根据 SQL 字符串匹配预设响应(如sql.Contains("SELECT * FROM Users")→ 返回new DataTable().AddRow(new User { Name = "Test" })) - 仓储类接收
IDbConnection或IConnectionFactory,测试时传入 fake 实例
重点测边界与异常,而非“能查出来”
避免写一堆“查一条用户返回不为空”的测试。真正要覆盖的是容易出错的环节:
- 空集合查询(
Query是否返回空 list 而非 null)("") - 参数为 null 时 SQL 是否报错(如
WHERE Id = @id,传入id = null,Dapper 默认转成WHERE Id = NULL—— 这是常见陷阱,应改用IS NULL) - 字段名与实体属性名不一致时,
[Column("user_name")]是否生效 - 复杂类型映射(如
User.Profile是子对象)是否正确填充
不测连接字符串和事务控制逻辑
连接打开/关闭、BeginTransaction、Commit 这些属于基础设施代码,不应放在仓储实现里。仓储方法应只专注 SQL 和映射;连接和事务由上层(如服务层或 UnitOfWork)管理。单元测试中也不必验证“是否调用了 Open()”,那属于集成测试范畴。
基本上就这些。不复杂但容易忽略——关键是把仓储当成纯数据搬运工来测,而不是把它和数据库绑死。










