cho*_*bo2 5 c# generics unit-testing entity-framework moq
我正在使用moq,ef 6和xunit.我发现自己一遍又一遍地编写这段代码,并认为我可以把它变成一种通用的方法但是有些麻烦.
public static void CreateSalesMock(List<Sale> sales, Mock<DatabaseContext> dbContextMock)
{
var data = sales.AsQueryable();
var mockSet = new Mock<DbSet<Sale>>();
mockSet.As<IQueryable<Sale>>()
.Setup(x => x.Provider)
.Returns(data.Provider);
mockSet.As<IQueryable<Sale>>()
.Setup(x => x.Expression)
.Returns(data.Expression);
mockSet.As<IQueryable<Sale>>()
.Setup(x => x.ElementType)
.Returns(data.ElementType);
mockSet.As<IQueryable<Sale>>()
.Setup(x => x.GetEnumerator())
.Returns(data.GetEnumerator());
dbContextMock.Setup(x => x.Sales).Returns(mockSet.Object);
}
Run Code Online (Sandbox Code Playgroud)
现在我在我的数据库中有许多其他表,所以如果我可以编写一个方法来接收该数据的列表并进行设置,那么我可以通过它进行模拟查询会很棒.
public static void CreateMockSet<T, TA, TB>(T dataList, TA model,
Func<TB> lambda, Mock<DatabaseContext> dbContextMock)
where T : List<T>
where TA: Mock<DbSet<TA>>
{
var data = dataList.AsQueryable();
model.As<IQueryable<T>>()
.Setup(x => x.Provider)
.Returns(data.Provider);
model.As<IQueryable<T>>()
.Setup(x => x.Expression)
.Returns(data.Expression);
model.As<IQueryable<T>>()
.Setup(x => x.ElementType)
.Returns(data.ElementType);
model.As<IQueryable<T>>()
.Setup(x => x.GetEnumerator())
.Returns(data.GetEnumerator());
dbContextMock.Setup(x => lambda);
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,我有这个,但我不确定这是否有效.我被困在传递"lambda"部分(x => x.Sales
例如),所以我甚至无法测试它.
Old*_*Fox 11
Tim Larson已经在他的博客中为这个样板代码提供了一个很好的解决方案:
public static class DbSetMocking
{
private static Mock<DbSet<T>> CreateMockSet<T>(IQueryable<T> data)
where T : class
{
var queryableData = data.AsQueryable();
var mockSet = new Mock<DbSet<T>>();
mockSet.As<IQueryable<T>>().Setup(m => m.Provider)
.Returns(queryableData.Provider);
mockSet.As<IQueryable<T>>().Setup(m => m.Expression)
.Returns(queryableData.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType)
.Returns(queryableData.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator())
.Returns(queryableData.GetEnumerator());
return mockSet;
}
public static IReturnsResult<TContext> ReturnsDbSet<TEntity, TContext>(
this IReturns<TContext, DbSet<TEntity>> setup,
TEntity[] entities)
where TEntity : class
where TContext : DbContext
{
Mock<DbSet<TEntity>> mockSet;
return ReturnsDbSet(setup, entities, out mockSet);
}
public static IReturnsResult<TContext> ReturnsDbSet<TEntity, TContext>(
this IReturns<TContext, DbSet<TEntity>> setup,
IQueryable<TEntity> entities)
where TEntity : class
where TContext : DbContext
{
Mock<DbSet<TEntity>> mockSet;
return ReturnsDbSet(setup, entities, out mockSet);
}
public static IReturnsResult<TContext> ReturnsDbSet<TEntity, TContext>(
this IReturns<TContext, DbSet<TEntity>> setup,
IEnumerable<TEntity> entities)
where TEntity : class
where TContext : DbContext
{
Mock<DbSet<TEntity>> mockSet;
return ReturnsDbSet(setup, entities, out mockSet);
}
public static IReturnsResult<TContext> ReturnsDbSet<TEntity, TContext>(
this IReturns<TContext, DbSet<TEntity>> setup,
TEntity[] entities, out Mock<DbSet<TEntity>> mockSet)
where TEntity : class
where TContext : DbContext
{
mockSet = CreateMockSet(entities.AsQueryable());
return setup.Returns(mockSet.Object);
}
public static IReturnsResult<TContext> ReturnsDbSet<TEntity, TContext>(
this IReturns<TContext, DbSet<TEntity>> setup,
IQueryable<TEntity> entities, out Mock<DbSet<TEntity>> mockSet)
where TEntity : class
where TContext : DbContext
{
mockSet = CreateMockSet(entities);
return setup.Returns(mockSet.Object);
}
public static IReturnsResult<TContext> ReturnsDbSet<TEntity, TContext>(
this IReturns<TContext, DbSet<TEntity>> setup,
IEnumerable<TEntity> entities, out Mock<DbSet<TEntity>> mockSet)
where TEntity : class
where TContext : DbContext
{
mockSet = CreateMockSet(entities.AsQueryable());
return setup.Returns(mockSet.Object);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在UT中,您将其用作以下内容:
var context = new Mock<DatabaseContext>();
context.setup(x => x.Sales).ReturnsDbSet(new List<Sale>(){put here the items..});
Run Code Online (Sandbox Code Playgroud)
编辑
我更新了代码.现在还有3个重载允许对DbSet<T>
属性进行验证:
[TestMethod]
public void TestMethod1()
{
var sales = new List<Sale>
{
new Sale() {id = 1},
new Sale() {id = 6},
new Sale() {id = 5},
new Sale() {id = 4},
new Sale() {id = 3},
new Sale() {id = 2}
};
var fakeContest = new Mock<SalesContext>();
Mock<DbSet<Sale>> fakeSet;
fakeContest.Setup(context => context.Sales).ReturnsDbSet(sales, out fakeSet);
var itemsToRemove = sales.Where(sale => sale.id%2 == 0);
fakeContest.Object.Sales.RemoveRange(itemsToRemove);
fakeSet.Verify(set => set.RemoveRange(itemsToRemove));
}
Run Code Online (Sandbox Code Playgroud)