2017-08-08 14 views
4

私はMoqが新しく、データのバッキングストアのように使用したいが、ライブデータベースには触れない。次のようにEntity FrameworkとMoqを使用してユニットテストを行うにはどうすればよいですか?

私のセットアップは次のとおりです。

  • AのUnitOfWorkは、すべてのリポジトリが含まれており、アプリケーション全体のデータアクセスのために使用されています。
  • リポジトリは、DbContextによって提供されるDbSetへの直接フ​​ックを表します。
  • DbContextにはすべてのDbSetsが含まれています。ここで

は、これまでのところ、私のテストです:それは、ユーザーがモックDbSetに追加されたことを確認することができますよう

 // ARRANGE 
     var user = new User() 
     { 
      FirstName = "Some", 
      LastName = "Guy", 
      EmailAddress = "[email protected]", 
     }; 

     var mockSet = new MockDbSet<User>(); 
     var mockContext = new Mock<WebAPIDbContext>(); 

     mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object); 

     // ACT 
     using (var uow = UnitOfWork.Create(mockContext.Object)) 
     { 
      uow.UserRepository.Add(user); 
      uow.SaveChanges(); 
     } 

     // ASSERT 
     mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once()); 

私のテストは、成功のようだ - しかし、私は何をする必要があるが、実際に取得することですそのデータを元に戻し、さらにアサーションを実行します(単なるアドホックテストです)。

フレームワークのテストが私の頭の中で行われていることをアドバイスしてください。また、使いやすくすれば他のテストフレームワークに移行することもできます。

ありがとうございます。

更新:ここに私の作業コードがあります。

ユニットテスト

 // ARRANGE 
     var user = new User() 
     { 
      FirstName = "Some", 
      LastName = "Guy", 
      EmailAddress = "[email protected]", 
     }; 

     var mockSet = new MockDbSet<User>(); 
     var mockContext = new Mock<WebAPIDbContext>(); 

     mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object); 

     // ACT 
     using (var uow = UnitOfWork.Create(mockContext.Object)) 
     { 
      uow.UserRepository.Add(user); 
      uow.SaveChanges(); 
     } 

     // ASSERT 
     mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once()); 

     // TODO: Further assertations can now take place by accessing mockSet.BackingStore. 
    } 

MockDbSet

class MockDbSet<TEntity> : Mock<DbSet<TEntity>> where TEntity : class 
{ 
    public ICollection<TEntity> BackingStore { get; set; } 

    public MockDbSet() 
    { 
     var queryable = (this.BackingStore ?? (this.BackingStore = new List<TEntity>())).AsQueryable(); 

     this.As<IQueryable<TEntity>>().Setup(e => e.Provider).Returns(queryable.Provider); 
     this.As<IQueryable<TEntity>>().Setup(e => e.Expression).Returns(queryable.Expression); 
     this.As<IQueryable<TEntity>>().Setup(e => e.ElementType).Returns(queryable.ElementType); 
     this.As<IQueryable<TEntity>>().Setup(e => e.GetEnumerator()).Returns(() => queryable.GetEnumerator()); 

     // Mock the insertion of entities 
     this.Setup(e => e.Add(It.IsAny<TEntity>())).Returns((TEntity entity) => 
     { 
      this.BackingStore.Add(entity); 

      return entity; 
     }); 

     // TODO: Other DbSet members can be mocked, such as Remove(). 
    } 
} 
+0

模擬データベースセットのコードを表示します。バッキングストアとして機能するコレクションを作成し、列挙型dbセットをバッキングコレクションでモックするだけで済みます。 – Nkosi

+0

申し訳ありません。私は自分の投稿を更新しました。 MockDbSetはテストされていません。なぜなら、どのようにして一緒に収まるかわからないからです。私は "クエリ可能な"変数がDbSetのためにそのように動作することを疑うだろう。 模擬DbSetにフックすることでバッキングストアとして機能するコレクションを作成するにはどうすればよいですか? – Rhonage

答えて

5

あなただけのバッキングストアとして機能し、バッキングコレクション

で列挙デシベルセットを模擬するために、コレクションを作成する必要があります
public class MockDbSet<TEntity> : Mock<DbSet<TEntity>> where TEntity : class { 
    public MockDbSet(List<TEntity> dataSource = null) { 
     var data = (dataSource ?? new List<TEntity>()); 
     var queryable = data.AsQueryable(); 

     this.As<IQueryable<TEntity>>().Setup(e => e.Provider).Returns(queryable.Provider); 
     this.As<IQueryable<TEntity>>().Setup(e => e.Expression).Returns(queryable.Expression); 
     this.As<IQueryable<TEntity>>().Setup(e => e.ElementType).Returns(queryable.ElementType); 
     this.As<IQueryable<TEntity>>().Setup(e => e.GetEnumerator()).Returns(() => queryable.GetEnumerator()); 
     //Mocking the insertion of entities 
     this.Setup(_ => _.Add(It.IsAny<TEntity>()).Returns((TEntity arg) => { 
      data.Add(arg); 
      return arg; 
     }); 

     //...the same can be done for other members like Remove 
    } 
} 

これでリストを使用してデータを保持することができます

// ARRANGE 
var dataSource = new List<User>(); //<-- this will hold data 
var user = new User() 
{ 
    FirstName = "Some", 
    LastName = "Guy", 
    EmailAddress = "[email protected]", 
}; 

var mockSet = new MockDbSet<User>(dataSource); 
var mockContext = new Mock<WebAPIDbContext>(); 

mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object); 

// ACT 
using (var uow = UnitOfWork.Create(mockContext.Object)) 
{ 
    uow.UserRepository.Add(user); 
    uow.SaveChanges(); 


    // ASSERT 
    mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once()); 
    Assert.IsTrue(dataSource.Contains(user)); //<-- shows mock actually added item 
    Assert.IsTrue(uow.UserRepository.Any(u => u == user)); //<-- show you can actually query mock DbSet 
} 
関連する問題