我正在为我的服务编写单元测试,它使用实体框架作为ORM与数据库通信。在我的服务中,有一段代码根据表动态投影以选择匿名类型对象,如下所示-
string selectQuery = "new ( " + string.Join(",", someColumns) + ")";
var values = await context.MyTable.Where(data => data.Id == someId).Select(selectQuery).ToListAsync();
这是因为我投影的列在编译时是未知的,并且在某些条件下可能会有所不同。使用上面的代码,生产代码按预期工作。
但是,它开始抛出
System.ArgumentException
当我运行我的测试时-
'类型的表达式'系统.集合.通用.IEnumerable“1[DynamicClass1]”不能用于返回类型'系统.集合.通用.IEnumerable`1[MyTable]'
var values = new List<MyTable>
{
new MyTable
{
Id = 1,
Column1 = value1,
Column2 = value2,
Column3 = value3,
Column4 = value4
},
new MyTable
{
Id = 2,
Column1 = value5,
Column2 = value6,
Column3 = value7,
Column4 = value8
}
}.AsQueryable();
var mockValues = new Mock<DbSet<MyTable>>();
mockValues.As<IDbAsyncEnumerable<T>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<T>(values.GetEnumerator()));
mockValues.As<IQueryable<T>>().Setup(m => m.Provider).Returns(new TestDbAsyncQueryProvider<T>(values.Provider));
mockValues.As<IQueryable<T>>().Setup(m => m.Expression).Returns(values.Expression);
mockValues.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(values.ElementType);
mockValues.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(values.GetEnumerator());
Mock<Context> contextMock = new Mock<Context>();
contextMock.Setup(x => x.MyTable).Returns(mockValues.Object);
var result = await _myService.SomeMethod(contextMock.Object, ...);
Assert.IsTrue(result);
我已经介绍了
Microsoft Documentation
async
支持我的测试。
通过查看异常,我猜这应该与我在这里使用的动态投影有关,所以我将服务中的代码改为-
var values = await context.MyTable.Where(data => data.Id == someId).Select(x => new { x.Id, x.Column1, x.Column2, x.Column4 }).ToListAsync();
这基本上消除了动态结构,正如我所料,它起了作用。
所以,问题是-有没有一种方法可以动态地投影列,并且仍然让我的测试工作。