一、前言

  在实际编写程序时,往往需要与数据库打交道,在单元测试中直接使用数据库又显得太重,如果可以方便的编写一些测试数据,这样更易于检测功能。如何模拟数据库行为便是本篇的主题。微软有教程说明Moq Entity Framework,需注意的是EF的版本必须是6以上。但在这篇教程中是直接使用DbContext,而自己的应用程序中都是用UnitOfWork模式。经过修改后也可以实现类似功能。

二、参考文献

https://msdn.microsoft.com/en-us/data/dn314429

三、采用UnitOfWork模式管理数据库

UnitOfWork

 public interface IDomainUnitOfWork : IDisposable
{
DbContext Db { get; }
//ImsDbContext dbContext { get; }
Task SaveChangesClientWinAsync();
Task SaveChangesDataBaseWinAsync(); void SaveChangesClientWin();
void SaveChangesDataBaseWin();
}

Repository接口

 public interface IDomainRepositoryAsync<T> where T : class
{ //Async Task<List<T>> GetAllAsync(Expression<Func<T, bool>> predicate = null); Task<T> SingleAsync(object primaryKey);
Task<T> SingleOrDefaultAsync(object primaryKey);
Task<bool> IsExistsAsync(Expression<Func<T, bool>> predicate = null); //同步
IQueryable<T> GetAll(Expression<Func<T, bool>> predicate = null);
T Single(object primaryKey);
T SingleOrDefault(object primaryKey);
bool IsExist(Expression<Func<T, bool>> predicate = null);
void Add(T entity);
void Update(T entity);
void Delete(T entity); }

Repository实现

public class DomainRepositoryAsync<T> : IDomainRepositoryAsync<T> where T : class
{
private readonly IDomainUnitOfWork _unitOfWork;
internal DbSet<T> dbSet; public DomainRepositoryAsync(IDomainUnitOfWork unitOfWork)
{
if (unitOfWork == null) throw new ArgumentNullException("unitOfWork");
this._unitOfWork = unitOfWork;
this.dbSet = _unitOfWork.Db.Set<T>();
}
public void Add(T entity)
{
dynamic obj = dbSet.Add(entity);
} public void Delete(T entity)
{
if (_unitOfWork.Db.Entry(entity).State == EntityState.Detached)
{
dbSet.Attach(entity);
}
dynamic obj = dbSet.Remove(entity);
} public async Task<List<T>> GetAllAsync(Expression<Func<T, bool>> predicate = null)
{ if (predicate != null)
{
return await this.dbSet.Where(predicate).ToListAsync();
} return await this.dbSet.ToListAsync();
} public async Task<bool> IsExistsAsync(Expression<Func<T, bool>> predicate = null)
{
var result = false;
if (predicate == null)
{
return result;
}
var query = await this.dbSet.Where(predicate).FirstOrDefaultAsync();
result = query == null ? false : true;
return result;
}
/// <summary>
/// 如果没有找到指定键元素,抛出异常.
/// </summary>
/// <param name="primaryKey">The primary key.</param>
/// <returns>Task&lt;T&gt;.</returns>
/// <exception cref="System.Collections.Generic.KeyNotFoundException"></exception>
public async Task<T> SingleAsync(object primaryKey)
{
T dbResult = null;
dbResult = await dbSet.FindAsync(primaryKey);
if (dbResult == null)
{
throw new KeyNotFoundException();
}
return dbResult;
} public async Task<T> SingleOrDefaultAsync(object primaryKey)
{
var dbResult = await dbSet.FindAsync(primaryKey);
return dbResult;
} public void Update(T entity)
{
this.dbSet.Attach(entity);
_unitOfWork.Db.Entry(entity).State = EntityState.Modified;
} public IQueryable<T> GetAll(Expression<Func<T, bool>> predicate = null)
{
if (predicate != null)
{
return this.dbSet.Where(predicate);
} return this.dbSet;
} public T Single(object primaryKey)
{
T dbResult = null;
dbResult = dbSet.Find(primaryKey);
if (dbResult == null)
{
throw new KeyNotFoundException();
}
return dbResult;
} public T SingleOrDefault(object primaryKey)
{
var dbResult = dbSet.Find(primaryKey);
return dbResult;
} public bool IsExist(Expression<Func<T, bool>> predicate = null)
{
var result = false;
if (predicate == null)
{
return result;
}
var query = this.dbSet.Where(predicate).FirstOrDefault();
result = query == null ? false : true;
return result;
}
}

DbContext

public class DurationDbContext : DbContext
{
public virtual DbSet<Department> Departments { get; set; }
public virtual DbSet<Duration> Durations { get; set; }
}

四、配置UnitTest

1、首先用Nuget安装moq

2、注意在DomainRepositoryAsync中有一个DbSet<T> dbSet,需要Moq的就是该类型,并且在DbContext中的必须加"virtual“关键字。

3、Moq代码

var unitOfWork = new Mock<IDomainUnitOfWork>();
var mockDepartment = SetupMockDbSet<Department>(DepartmentList);
var mockDuration = SetupMockDbSet<Duration>(DurationList);
unitOfWork.Setup(m => m.Db.Set<Department>()).Returns(mockDepartment.Object);
unitOfWork.Setup(m => m.Db.Set<Duration>()).Returns(mockDuration.Object);

在教程中说到了如何处理异步的查询操作,教程很详细,此处便不再重复,直接将代码Copy到单元测试工程中即可,再将重复的代码作为一个方法SetupMockDBSet。

 public static Mock<DbSet<T>> SetupMockDbSet<T>(List<T> dataList) where T : class
{
var data = dataList.AsQueryable();
var mockSet = new Mock<DbSet<T>>();
mockSet.As<IDbAsyncEnumerable<T>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<T>(data.GetEnumerator())); mockSet.As<IQueryable<T>>()
.Setup(m => m.Provider)
.Returns(new TestDbAsyncQueryProvider<T>(data.Provider)); mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
return mockSet;
}

注意在配置UnitOfWork时,用Setup中是对IUnitOfWork的Db进行设置。接下来的实现方式与教程相同,不再重复。

利用Mocking Framework 单元测试Entity Framework的更多相关文章

  1. [Entity Framework] MySQL @ Entity Framework 6

    原文 [Entity Framework] MySQL @ Entity Framework 6 要让MySQL能够用EF6,我花了一点时间,在此记录一下 安装元件 在设定档加入Provider 安装 ...

  2. Entity Framework 教程——Entity Framework中的实体类型

    Entity Framework中的实体类型 : 在之前的章节中我们介绍过从已有的数据库中创建EDM,它包含数据库中每个表所对应的实体.在EF 5.0/6.0中,存在POCO 实体和动态代理实体两种. ...

  3. 【Entity Framework】 Entity Framework资料汇总

    Fluent API : http://social.msdn.microsoft.com/Search/zh-CN?query=Fluent%20API&Refinement=95& ...

  4. 基于Entity Framework 6的框架Nido Framework

    随着 Entity Framework 最新主版本 EF6 的推出,Microsoft 对象关系映射 (ORM) 工具达到了新的专业高度,与久负盛名的 .NET ORM 工具相比已不再是门外汉. EF ...

  5. 8天掌握EF的Code First开发之Entity Framework介绍

    返回<8天掌握EF的Code First开发>总目录 本篇目录 Entity Framework概要 什么是ORM Entity Framework简史 Entity Framework具 ...

  6. ADO.NET Entity Framework

    ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R Mapping) 解决方案, 早期被称为 ObjectSpace,现已经包含在 V ...

  7. 转载 8天掌握EF的Code First开发之Entity Framework介绍

    转载原地址:  http://www.cnblogs.com/farb/p/IntroductionToEF.html Entity Framework概要 Entity Framework是微软的O ...

  8. Entity Framework开发介绍

    一.Entity Framework概要 Entity Framework是微软的Object Relational Mapper(对象关系映射),也就是我们平常说的ORM,它可以让应用程序开发者将关 ...

  9. 深入了解Entity Framework框架及访问数据的几种方式

    一.前言 1.Entity Framework概要 Entity Framework是微软以ADO.NET为基础所发展出来的对象关系映射(O/R Mapping)解决方案.该框架曾经为.NET Fra ...

随机推荐

  1. Vue踩坑系列

    前言 前端开发对于vue的使用已经越来越多,它的优点就不做介绍了, 本篇是我对vue使用过程中遇到的问题中做的一些总结,帮助大家踩坑.如果喜欢的话可以点波赞,或者关注一下,希望本文可以帮到大家!!! ...

  2. LC 163. Missing Ranges 【lock, hard】

    Given a sorted integer array nums, where the range of elements are in the inclusive range [lower, up ...

  3. 在smarty模板中截取指定长度的字符串

    在smarty模板中截取指定长度的字符串,可使用truncate这个插件. 用法: {{$data.value|truncate:28:'...'}} 28个字节14个字数输出,多余部分输出...,一 ...

  4. springBoot整合spring、springMVC、mybatis

    前文 1.为什么使用springBoot 众所周知,spring是Java在搭建后台时非常实用的框架,其整合了市场上几乎所有的主流框架于一体,使后端编程更加高效.快速: 而SpringBoot更是把s ...

  5. Eclipse使用git发布项目到github

    因为一直都在使用svn,今天尝试了下git,记录下来既是方便自己以后查看,也是分享一些经验! 废话不多说,撸起袖子就是干!!! 1.选中要上传的项目右键 2.选中git 3.在图上打钩,点击所要上传的 ...

  6. Pythonnumpy提取矩阵的某一行或某一列的实例

    Python numpy 提取矩阵的某一行或某一列的实例 下面小编就为大家分享一篇Python numpy 提取矩阵的某一行或某一列的实例,具有很好的参考价值,希望对大家有所帮助.一起跟随小编过来看看 ...

  7. JavaScript(4):正则表达式

    基础方法 <!DOCTYPE html> <html> <body> <p>类型及转换</p> <script> // 正则表达 ...

  8. 【转】一次HBase问题的解决过程(Status: INCONSISTENT)

    [From]https://www.cnblogs.com/quchunhui/p/9583746.html ==版本信息== HBase:2.7.1 Storm:1.0.1 RocketMQ:3.4 ...

  9. Python的Multiprocessing多进程实例

    最近在拜读RBG大神的faster-rcnn源码时发现他用了多进程去分阶段处理神经网络,原因如下: # ------------------------------------------------ ...

  10. 不可不知的JavaScript - 闭包函数

    闭包函数 什么是闭包函数? 闭包函数是一种函数的使用方式,最常见的如下: function fn1(){ function fn(){ } return fn; } 这种函数的嵌套方式就是闭包函数,这 ...