2017-08-08 97 views
4

我是Moq的新手,想要將它用作數據的後備存儲 - 但不觸及實時數據庫。如何使用Entity Framework和Moq進行單元測試?

我的設置如下:

  • 一個的UnitOfWork包含所有存儲庫,並用於整個應用程序的數據訪問。
  • 存儲庫表示直接掛鉤到由DbContext提供的DbSet。
  • DbContext包含所有的DbSets。

這裏是我的測試,到目前爲止:

 // 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()); 

我的測試似乎是成功的,因爲它可以驗證用戶添加到模擬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()); 

     // 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設置代碼。您只需創建一個集合來充當後備存儲並模擬使用後備集合設置的枚舉db。 – Nkosi

+0

對不起。我已更新我的帖子。 MockDbSet未經測試,因爲我不太確定它是如何融合在一起的。我懷疑「可查詢」變量對於DbSet是如此。 我該如何去創建一個集合作爲後臺存儲掛鉤到模擬DbSet? – Rhonage

回答

5

你只需要創建一個集合作爲後備存儲,並嘲笑枚舉dB設置與襯裏收集

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 
} 
相關問題