我使用moq,ef 6和xunit。我發現自己一遍又一遍地寫這些代碼,並認爲我可以把它變成一個通用的方法,但有一些麻煩。如何將此EF Mock設置代碼編寫爲可重用的通用Boilerplate?
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);
}
現在我有很多其他表在我的數據庫,所以如果我能寫,將採取在數據列表和設定,讓我可以模擬查詢通過這將是巨大的一種方法。
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);
}
到目前爲止,我有,但我不知道如果這將工作與否。我被卡住在「lambda」部分(例如x => x.Sales
),所以我甚至無法測試它。在UT
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);
}
}
然後你使用它,如下所示::
我想你想改變'where'約束引入一個接口:'其中T:列表'。 –
我建議看看Builder模式請參閱https://www.kenneth-truyers.net/2013/07/15/flexible-and-expressive-unit-tests-with-the-builder-pattern/ –
@ ToddSprang我不確定IBase會是什麼。你可以舉更多的例子 – chobo2