2016-12-25 15 views
0

以下は、メモリ内のdbsetsでサポートされていない.ToListAsync()のために.ShouldNotThrow()が失敗するテストの種類です(私は正確な文言は便利ですが、あなたは写真を手に入れます)。それが重要な場合は、Entity Framework verによって提供されるdbsetをモックアップしようとしています。 6.1.3:ユニットテスト.ToListAsync()をメモリ内で使用する

[TestFixture] 
public class Tests 
{ 
    private SomeRepository _repository; 
    private Mock<DbSet<SomeEntity>> _mockDbSet; 
    private Mock<IApplicationDbContext> _mockAppDbContext; 

    [OneTimeSetUp] 
    public void TestFixtureSetUp() 
    { 
     _mockDbSet = new Mock<DbSet<SomeEntity>>(); 
     _mockAppDbContext = new Mock<IApplicationDbContext>(); 
     _mockAppDbContext.SetupGet(c => c.Gigs).Returns(_mockGigsDbSet.Object); 

     _repository = new SomeRepository(_mockAppDbContext.Object); 
    } 

    [Test] 
    public void Test() 
    { 
     // Setup 
     var results = (IEnumerable<SomeEntity>) null; 
     var singleEntity = new SomeEntity {Id = "1"}; 
     _mockDbSet.SetSource(new List<SomeEntity> { singleEntity }); 

     // Act 
     var action = new Func<Task>(async() => 
     { 
      results = await _repository.GetMultipleAsync(); //this ends up calling "await mockDbSet.ToListAsync().ConfigureAwait(false)" internally 
     }); 

     // Verify 
     action.ShouldNotThrow(); //an exception is thrown about .ToListAsync() not being supported by in-memory dbsets or something to that effect 
     results.Should().BeEmpty(); 
    } 
} 

.ToList(場合は意図したように上記試験の動作)は非同期ベース.ToListAsync()の代わりに同期して使用されます。また、実際のasp.net内から使用すると、リポジトリも正常に動作します。

これらの単体テストで動作するように.ToListAsync()のdbsetをモックアップする正しい方法は何ですか?

PS:私はユニットテストしてきたプロジェクトでは、ここで見つけることができます:.ToListAsync(による失敗

 https://bitbucket.org/dsidirop/gighub 

ユニットテストは)コメントでマークされているが「当分の間、失敗しました'

+3

EF DbContextを完全にモックするために飛び越すためのフープがたくさんあります。リンクのみの回答は歓迎されていますが、これは電話で入力する情報の多くですから、コメントとして残しておきます。 [EF DbContextを嘲笑](https://msdn.microsoft.com/en-us/library/dn314429(v=113).aspx)。 –

答えて

2

帽子:

https://msdn.microsoft.com/en-us/library/dn314429(v=vs.113).aspx

をリポジトリの非同期メソッドのためのユニットテストを作成するための適切な方法は、最初にこれらのユーティリティ・モックアップクラスを作成する方法その後、

using System.Collections.Generic; 
using System.Data.Entity.Infrastructure; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Threading; 
using System.Threading.Tasks; 

namespace TestingDemo 
{ 
    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; } 
     } 
    } 
} 

そしてそうのようにそれらを使用します。

using Microsoft.VisualStudio.TestTools.UnitTesting; 
using Moq; 
using System.Collections.Generic; 
using System.Data.Entity; 
using System.Data.Entity.Infrastructure; 
using System.Linq; 
using System.Threading.Tasks; 

namespace TestingDemo 
{ 
    [TestClass] 
    public class AsyncQueryTests 
    { 
     [TestMethod] 
     public async Task GetAllBlogsAsync_orders_by_name() 
     { 

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

      var mockSet = new Mock<DbSet<Blog>>(); 
      mockSet.As<IDbAsyncEnumerable<Blog>>() 
       .Setup(m => m.GetAsyncEnumerator()) 
       .Returns(new TestDbAsyncEnumerator<Blog>(data.GetEnumerator())); 

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

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

      var mockContext = new Mock<BloggingContext>(); 
      mockContext.Setup(c => c.Blogs).Returns(mockSet.Object); 

      var service = new BlogService(mockContext.Object); 
      var blogs = await service.GetAllBlogsAsync(); 

      Assert.AreEqual(3, blogs.Count); 
      Assert.AreEqual("AAA", blogs[0].Name); 
      Assert.AreEqual("BBB", blogs[1].Name); 
      Assert.AreEqual("ZZZ", blogs[2].Name); 
     } 
    } 
} 
+0

リンク以外のいくつかの詳細が追加された場合、私はこの回答に投票します。 – jpierson

+0

あなたのリクエストごとに受け入れられた回答を更新しました。 – xDisruptor

1

Entity Framework(つまりMicrosoftの仕事)ではなく、アプリケーション(ロジック)の単体テストに焦点を当てる必要があります。あなたの(アプリケーション)ビジネスロジックのための単体テストを書くときに、そのインタフェースを遠ざけることができるように、データレイヤ用の素敵なインターフェイスを追加してください。正しい答えを提供するためのブラッドフォードディロンにオフ

+0

私はあなたの考え方を理解していますが、私は自分自身のように行ってしまいましたが、私は複数形で人々の提案を研究し、これまでのところ、元の投稿に表示されたようにしてください。マイクロソフトでさえ、dbsetとefを嘲笑することは一般的だと認識しているようです(https://msdn.microsoft.com/en-us/library/dn314429(v=vs.113).aspx)。リポジトリの実装と、「インタフェースされた」データ層のアプローチについて、私がリソースショーを指摘するのに十分親切になりますか? (私は車輪を作り直してnoobish blundersを作ってはいけません) – xDisruptor

+0

私はそれがあなたのアプリケーションの仕組みとあなたの時間を費やしているものに依存していると思います。私にはあなたが投稿したテストとmsdnページにあるものだけが、モックを使って物をメモリに保存できることを証明しました。それがあなたが望むものなら、私はEFを嘲笑するためのガイドを見つけることをお勧めします。私のアプリケーションでは、データスーレ(データベース、ディスク上のファイル、サービスを呼び出すかどうかなど)を変更できるように、インターフェイスの背後にあるデータアクセスを分離して(ビジネスロジックには意味がある)それから私は自分のビジネスロジックをテストする単体テストを書いています。しかし、私はコアビジネスとしてデータアクセスが表示されません... – Jocke

関連する問題