单元测试中使用Moq对EF的DbSet进行Mock
作者:网络转载 发布时间:[ 2016/2/29 14:10:02 ] 推荐标签:软件测试 单元测试
解决问题
那如何mock呢?比想象中复杂得多,幸好在msdn网站上发现了现成的mock实现代码(详见 Testing with a mocking framework ),照此可以轻松mock。
mock之前需要实现这三个接口:IDbAsyncEnumerator,IDbAsyncEnumerable,IDbAsyncQueryProvider 。
1)TestDbAsyncEnumerator 实现 IDbAsyncEnumerator
public class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public TestDbAsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public void Dispose()
{
_inner.Dispose();
}
public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
public T Current
{
get { return _inner.Current; }
}
object IDbAsyncEnumerator.Current
{
get { return Current; }
}
}
2)TestDbAsyncEnumerable 实现 IDbAsyncEnumerable
public class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T>
{
public TestDbAsyncEnumerable(IEnumerable<T> enumerable)
: base(enumerable)
{ }
public TestDbAsyncEnumerable(Expression expression)
: base(expression)
{ }
public IDbAsyncEnumerator<T> GetAsyncEnumerator()
{
return new TestDbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
{
return GetAsyncEnumerator();
}
IQueryProvider IQueryable.Provider
{
get { return new TestDbAsyncQueryProvider<T>(this); }
}
}
3)TestDbAsyncQueryProvider 实现 IDbAsyncQueryProvider
public class TestDbAsyncQueryProvider<TEntity> : IDbAsyncQueryProvider
{
private readonly IQueryProvider _inner;
public TestDbAsyncQueryProvider(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
return new TestDbAsyncEnumerable<TEntity>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new TestDbAsyncEnumerable<TElement>(expression);
}
public object Execute(Expression expression)
{
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression)
{
return _inner.Execute<TResult>(expression);
}
public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute(expression));
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute<TResult>(expression));
}
}
然后将之前的mock代码:
var mockUnitOfWork = new Mock<IUnitOfWork>();
mockUnitOfWork.Setup(u => u.Set<BlogCategory>()).Returns(blogCategories);
改为下面的代码:
#region mockSet
var mockSet = new Mock<DbSet<BlogCategory>>();
mockSet.As<IDbAsyncEnumerable<BlogCategory>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<BlogCategory>(blogCategories.GetEnumerator()));
mockSet.As<IQueryable<BlogCategory>>()
.Setup(m => m.Provider)
.Returns(new TestDbAsyncQueryProvider<BlogCategory>(blogCategories.Provider));
mockSet.As<IQueryable<BlogCategory>>().Setup(m => m.Expression).Returns(blogCategories.Expression);
mockSet.As<IQueryable<BlogCategory>>().Setup(m => m.ElementType).Returns(blogCategories.ElementType);
mockSet.As<IQueryable<BlogCategory>>().Setup(m => m.GetEnumerator()).Returns(blogCategories.GetEnumerator());
#endregion
var mockUnitOfWork = new Mock<IUnitOfWork>();
mockUnitOfWork.Setup(u => u.Set<BlogCategory>()).Returns(mockSet.Object);
这样成功mock出DbSet之后,单元测试成功通过,问题解决了。
1 passed, 0 failed, 0 skipped, took 2.75 seconds (xUnit.net 1.9.2 build 1705).
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
iOS单元测试mocha、chai、sinon和istanbul实现百分之百的单元测试覆盖率关于单元测试的总结及思考编写更好的Java单元测试的7个技巧Android单元测试框架Robolectric3.0介绍(一)使用Kiwi单元测试总结单元测试如此重要,为什么你不知道Python单元测试??使用装饰器实现测试跳过和预期故障对Controller的单元测试写好单元测试的10个技巧单元测试的重要性Angular单元测试系列??Component、Directive、Pipe 以及ServiceAndroid单元测试的整理提升单元测试体验的利器--Mockito使用总结iOS UnitTest单元测试Vue的单元测试探索(二)

sales@spasvo.com