我的课堂上有以下方法代码:
public async Task<int> TestMethodAsync()
{
var code = await Context.DataCodes
.Include(x => x.Text)
.Where(x => x.Code == "HI")
.ToListAsync();
return 1;
}
public int TestMethod()
{
var code = Context.DataCodes
.Include(x => x.Text)
.Where(x => x.Code == "HI")
.ToList();
return 1;
}
以及以下单元测试类:
namespace ControllerUnitTests.ServiceTests
{
[TestFixture]
class UsersServiceTests
{
private IDataContext<ClearviewLocalContext> _context;
private Mock<ClearviewLocalContext> _dbContext;
private Mock<IDescriptionService> _descriptionService;
private Mock<IFilterService> _filterService;
private Mock<IApplicationUserService> _userService;
private Mock<IGroupingService> _groupingService;
private Mock<ISelectionListsService> _selectionService;
private Mock<IActionLogService> _actionLogService;
private IAuditService _auditService;
/// <summary>
/// Constructor
/// </summary>
[SetUp]
public void setup()
{
_dbContext = new Mock<ClearviewLocalContext>();
_descriptionService = new Mock<IDescriptionService>();
_filterService = new Mock<IFilterService>();
_userService = new Mock<IApplicationUserService>();
_groupingService = new Mock<IGroupingService>();
_selectionService = new Mock<ISelectionListsService>();
_actionLogService = new Mock<IActionLogService>();
var dataCodesLists = new List<t_Data_DataCodes>();
dataCodesLists.Add(new t_Data_DataCodes { UNID = 1, Code = "HI" });
var dbDataCodesLists = MockDbSet.GetQueryableMockDbSet(dataCodesLists);
_dbContext.Setup(x => x.DataCodes).Returns(dbDataCodesLists.Object);
_context = new DataContext<ClearviewLocalContext, ClearviewLocalContext>(_dbContext.Object);
_auditService = new AuditService(_context, _descriptionService.Object, _filterService.Object, _userService.Object, _groupingService.Object, _selectionService.Object, _actionLogService.Object);
}
[Test]
public async Task TestAsync()
{
var res = await _auditService.TestMethodAsync();
Assert.That(res == 1);
}
[Test]
public async Task Test()
{
var res = _auditService.TestMethod();
Assert.That(res == 1);
}
}
}
使用:
public static Mock<DbSet<T>> GetQueryableMockDbSet<T>(List<T> sourceList) where T : class
{
var queryable = sourceList.AsQueryable();
var dbSet = new Mock<DbSet<T>>();
dbSet.As<IDbAsyncEnumerable<T>>().Setup(m => m.GetAsyncEnumerator()).Returns(new TestDbAsyncEnumerator<T>(queryable.GetEnumerator()));
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(new TestDbAsyncQueryProvider<T>(queryable.Provider));
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
dbSet.Setup(x => x.Include(It.IsAny<string>())).Returns(dbSet.Object);
dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => sourceList.Add(s));
return dbSet;
}
最后:
namespace ControllerUnitTests.Helpers
{
internal class TestDbAsyncQueryProvider<TEntity> : IDbAsyncQueryProvider
{
private readonly IQueryProvider _inner;
internal 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));
}
}
internal 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); }
}
}
internal 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; }
}
}
}
类TestDbAsyncQueryProvider
是该站点https://msdn.microsoft.com/en-gb/data/dn314429的复制和粘贴
最后我的单元测试:
[Test]
public async Task TestAsync()
{
var res = await _auditService.TestMethodAsync();
Assert.That(res == 1);
}
[Test]
public async Task Test()
{
var res = _auditService.TestMethod();
Assert.That(res == 1);
}
问题是TestAsync
抛出以下异常:
The source IQueryable doesn't implement IDbAsyncEnumerable<ClearviewLocal_Core_DAL.TableModels.t_Data_DataCodes>. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see
但是据我所知,我已经在我的TestDbAsyncQueryProvider
类中实现了该功能-正如我上面所说的,这是一个复制和粘贴工作-我真的不知道它在做什么。
进一步说明-Test()
有效,如果我从Where
中删除TestAsync
子句也有效。
因此,问题似乎来自Where
和Async
的结合,但我不知道如何解决此问题-我们将不胜感激。