2014-10-10 415 views
8

我正在嘗試使用FakeDbSet爲單元測試製作FakeDbContext。IDbAsyncEnumerable not implemented

但我得到以下錯誤(見下文)。我正在擴展DbSet,因此通常應該實現IDbAsyncEnumerable。當我實施它時,它說它沒有用處。

例外:

System.InvalidOperationException:源的IQueryable不 實現 IDbAsyncEnumerable。實現IDbAsyncEnumerable的源只有 可用於實體 框架異步操作。詳情請參閱 http://go.microsoft.com/fwlink/?LinkId=287068

FakeDbSet類:

public abstract class FakeDbSet<TEntity> : DbSet<TEntity>, IEnumerable<TEntity>, IQueryable, IDbAsyncEnumerable<TEntity> where TEntity : Entity, new() 
{ 
    #region Private Fields 
    private readonly ObservableCollection<TEntity> _items; 
    private readonly IQueryable _query; 
    #endregion Private Fields 

    protected FakeDbSet() 
    { 
     _items = new ObservableCollection<TEntity>(); 
     _query = _items.AsQueryable(); 
    } 

    public Expression Expression { get { return _query.Expression; } } 

    public Type ElementType { get { return _query.ElementType; } } 

    public IQueryProvider Provider { get { return _query.Provider; } } 

    public override TEntity Add(TEntity entity) 
    { 
     _items.Add(entity); 
     return entity; 
    } 

    public override TEntity Remove(TEntity entity) 
    { 
     _items.Remove(entity); 
     return entity; 
    } 

    public override TEntity Attach(TEntity entity) 
    { 
     switch (entity.ObjectState) 
     { 
      case ObjectState.Modified: 
       _items.Remove(entity); 
       _items.Add(entity); 
       break; 

      case ObjectState.Deleted: 
       _items.Remove(entity); 
       break; 

      case ObjectState.Unchanged: 
      case ObjectState.Added: 
       _items.Add(entity); 
       break; 

      default: 
       throw new ArgumentOutOfRangeException(); 
     } 
     return entity; 
    } 

    public override TEntity Create() { return new TEntity(); } 

    public override TDerivedEntity Create<TDerivedEntity>() { return Activator.CreateInstance<TDerivedEntity>(); } 

    public override ObservableCollection<TEntity> Local { get { return _items; } } 

    IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator() 
    { 
     return _items.GetEnumerator(); 
    } 

    Type IQueryable.ElementType 
    { 
     get { return _items.AsQueryable().ElementType; } 
    } 

    Expression IQueryable.Expression 
    { 
     get { return _items.AsQueryable().Expression; } 
    } 

    IQueryProvider IQueryable.Provider 
    { 
     get { return _items.AsQueryable().Provider; } 
    } 

這裏是代碼中的要點。在要點的最後一個文件中,這是錯誤發生的地方。 Gist code

回答

21

你的情況是在具有異常消息(http://go.microsoft.com/fwlink/?LinkId=287068)的鏈接中明確提到。缺少的成分是您應該從Provider屬性返回的IDbAsyncQueryProvider。

只需通過鏈接導航到達the boilerplate implementation

小我可以加入,我只是引用的基本短語:

爲了使用,我們需要做一些更多的工作異步查詢。如果我們試圖使用我們的Moq DbSet和GetAllBlogsAsync方法,我們會得到以下異常:

System.InvalidOperationException:源IQueryable未實現IDbAsyncEnumerable。只有實現IDbAsyncEnumerable的源才能用於實體框架異步操作。欲瞭解更多詳情,請參閱http://go.microsoft.com/fwlink/?LinkId=287068

爲了使用,我們需要創建一個內存DbAsyncQueryProvider處理異步查詢的異步方法。雖然可以使用Moq設置查詢提供程序,但在代碼中創建測試雙重實現要容易得多。此實現的代碼如下:

等等

+0

我確實添加了所給的類,但我不知道如何將它與我的測試連接起來。我目前不使用moq。我將把所有的代碼添加到問題中。 @Hans帕桑特 – kevingoos 2014-10-13 07:29:47

+0

Passent:https://gist.github.com/ghost606/36718ff9670aad9c4f2e#file-searchdoubtfuls-cs – kevingoos 2014-10-13 07:52:14

1

DbSet可能實現IDbSet含蓄地讓這些方法在派生類中不可用於interface mapping

不得自IDbSet<TEntity>

You cannot call the explicitly implemented interface members of IDbSet from a re-implementation of that interface.

+0

我修復了這個錯誤,但現在我又回到了同一個錯誤xD上我將修改我的帖子並修改我所做的修改。 – kevingoos 2014-10-10 11:15:34

+0

btw正如你所看到的,我刪除了IDbSet實現。 – kevingoos 2014-10-10 11:17:26

3

使用微軟上面討論的樣板代碼的人只是注意,這裏是一個快速助手類,它可以改變你的嘲笑了數據進入異步結果。只需添加到MS代碼底部,並呼籲有類似

 var fakeDateAsMockAsyncQueryResult = new MockAsyncData<SomeType>().MockAsyncQueryResult(fakeDataList.AsQueryable()); 

.......

internal class MockAsyncData<T> where T : class 
{ 
    public Mock<DbSet<T>> MockAsyncQueryResult(IQueryable<T> data) 
    { 
     var mockSet = new Mock<DbSet<T>>(); 

     mockSet.As<IDbAsyncEnumerable<T>>() 
      .Setup(m => m.GetAsyncEnumerator()) 
      .Returns(new TestDbAsyncEnumerator<T>(data.GetEnumerator())); 

     mockSet.As<IQueryable<T>>() 
      .Setup(m => m.Provider) 
      .Returns(new TestDbAsyncQueryProvider<T>(data.Provider)); 

     mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression); 
     mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType); 
     mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); 

     return mockSet; 
    } 
} 

這是相同的代碼,在MS的例子,但通用和許多可重用不同的單元測試。

+0

什麼是TestDbAsyncEnumerator和TestDbAsyncQueryProvider? – user441521 2017-03-24 19:24:20

+0

我有和User441521一樣的問題。 TestDbAsyncEnumerator和TestDbAsyncQueryProvider都未定義。 – 2017-06-09 16:48:48

+0

@PaulGorbas和其他人想知道。缺少類* TestDbAsyncEnumerator *和* TestDbAsyncQueryProvider *在Microsoft指導https://msdn.microsoft.com/en-us/library/dn314429(v=vs.113).aspx提供。您需要將代碼複製到您自己的項目中。 – Jasen 2017-06-23 01:40:13

3

要解決我的IDbAsyncEnumerable問題:

  1. 改變了我的項目的目標從.NetFramework 4.0.NetFramework 4.5

  2. 重新安裝的EntityFramework 6.1.3NuGet包

  3. 在這一點上,我的Visual Studio的IDE 顯示Potencial修復顧問,讓我引用System.Data.Entity.Infrastructure命名空間

使用System.Data.Entity.Infrastructure;

+0

你如何使用它? – tofutim 2018-01-02 19:09:26

+0

Hi @tofutim。對於遲到的反應抱歉。你還在面對這個問題嗎? – 2018-01-07 14:43:16

1

我改名爲示例測試類從here,因爲它們是測試的有用以外,以除去字Test

  • DbAsyncEnumerable
  • DbAsyncEnumerator<T>
  • DbAsyncQueryProvider<TEntity>

然後我添加了擴展類be低,所以你現在只是做...

var data = new List<Blog> 
{ 
    new Blog { Name = "BBB" }, 
    new Blog { Name = "ZZZ" }, 
    new Blog { Name = "AAA" }, 
}.AsAsyncQueryable(); // <<== new extension method 

這不僅在單元測試中非常有用,而且當你想要實現的IQueryable<T>接口,要麼返回一個異步數據庫查詢或內存中的數據,您可以隨後安全地稱爲query.ToAsyncArray()

public static class AsyncQueryableExtensions 
{ 
    public static IQueryable<TElement> AsAsyncQueryable<TElement>(this IEnumerable<TElement> source) 
    { 
     return new DbAsyncEnumerable<TElement>(source); 
    } 

    public static IDbAsyncEnumerable<TElement> AsDbAsyncEnumerable<TElement>(this IEnumerable<TElement> source) 
    { 
     return new DbAsyncEnumerable<TElement>(source); 
    } 

    public static EnumerableQuery<TElement> AsAsyncEnumerableQuery<TElement>(this IEnumerable<TElement> source) 
    { 
     return new DbAsyncEnumerable<TElement>(source); 
    } 

    public static IQueryable<TElement> AsAsyncQueryable<TElement>(this Expression expression) 
    { 
     return new DbAsyncEnumerable<TElement>(expression); 
    } 

    public static IDbAsyncEnumerable<TElement> AsDbAsyncEnumerable<TElement>(this Expression expression) 
    { 
     return new DbAsyncEnumerable<TElement>(expression); 
    } 

    public static EnumerableQuery<TElement> AsAsyncEnumerableQuery<TElement>(this Expression expression) 
    { 
     return new DbAsyncEnumerable<TElement>(expression); 
    } 
} 
相關問題