使用MOQ同步方法测试EF异步方法

我有这个方法:

public async Task DeleteUserAsync(Guid userId) { using (var context = this.contextFactory.Create()) { var user = await context.Users.FirstOrDefaultAsync(x => x.Id.Equals(userId)); if (user == null) { throw new Exception("User doesn't exist"); } context.Users.Remove(user); await context.SaveChangesAsync(); } } 

我想测试一下。 所以我创建了测试:

  [TestMethod] public async Task DeleteUsersSuccessfulCallTest() { // Arrange var id = Guid.NewGuid(); var user = new User() { Id = id }; var context = new Mock(); var usersDbSet = DbSetQueryMocking.GenericSetupAsyncQueryableMockInterfaceSet(new List { user }.AsQueryable()); context.Setup(x => x.Users).Returns(usersDbSet.Object); context.Setup(x => x.Users.Remove(user)).Returns(user).Verifiable(); context.Setup(x => x.SaveChangesAsync()).ReturnsAsync(1).Verifiable(); this.contextFactory.Setup(x => x.Create()).Returns(context.Object); // Act await this.userService.DeleteUserAsync(id); context.VerifyAll(); } } 

我有这个方法来创建一个模拟集:

  public static Mock<DbSet> GenericSetupAsyncQueryableMockSet(IQueryable data) where T : class { var mockSet = new Mock<DbSet>(); mockSet.As<IDbAsyncEnumerable>().Setup(m => m.GetAsyncEnumerator()).Returns(new TestDbAsyncEnumerator(data.GetEnumerator())); mockSet.As<IQueryable>().Setup(m => m.Provider).Returns(new TestDbAsyncQueryProvider(data.Provider)); mockSet.As<IQueryable>().Setup(m => m.Expression).Returns(data.Expression); mockSet.As<IQueryable>().Setup(m => m.ElementType).Returns(data.ElementType); mockSet.As<IQueryable>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); return mockSet; } 

但是,因为我的DeleteUserAsync包含异步扩展方法和标准同步方法,所以我收到以下错误消息:

System.InvalidOperationException:源IQueryable的提供程序未实现IDbAsyncQueryProvider。 只有实现IDbAsyncQueryProvider的提供程序才能用于Entity Framework异步操作。 有关详细信息,请参阅http://go.microsoft.com/fwlink/?LinkId=287068 。

显然,如果我只是设置DbSet并使用Queryable DbSet掉,那么它将抛出相同的exception。

仅供参考:违规行是:

 context.Setup(x => x.Users.Remove(user)).Returns(user).Verifiable(); 

有这条线:错误

没有它:成功的测试。

我该如何解决?

.AsQueryable()生成的EnumerableQuery类不实现IDbAsyncQueryProvider但很容易通过实现扩展EnumerableQuery 。 创建其中一个而不是调用.AsQueryable()来包装您的集合。 我在下面有一个实现,它进一步扩展到一个IDbSet但你可能不需要走那么远。

 class StubSet : EnumerableQuery, IDbSet, IDbAsyncQueryProvider where T : class { public StubSet(IEnumerable collection) : base(collection) { Local = new ObservableCollection(collection); } public ObservableCollection Local { get; private set; } public T Find(params object[] keyValues) { throw new NotImplementedException(); } public T Add(T entity) { Local.Add(entity); return entity; } public T Remove(T entity) { Local.Remove(entity); return entity; } public T Attach(T entity) { return Add(entity); } public T Create() { throw new NotImplementedException(); } public TDerivedEntity Create() where TDerivedEntity : class, T { throw new NotImplementedException(); } public void DeleteObject(T entity) { throw new NotImplementedException(); } public void Detach(T entity) { throw new NotImplementedException(); } async Task IDbAsyncQueryProvider.ExecuteAsync(Expression expression, CancellationToken cancellationToken) { return ((IQueryProvider)this).Execute(expression); } async Task IDbAsyncQueryProvider.ExecuteAsync(Expression expression, CancellationToken cancellationToken) { return ((IQueryProvider)this).Execute(expression); } }