2017-06-29 83 views
4

我想單元測試從嘲笑DbContext存儲庫的檢索方法,但我不能將模擬DbSet值設置到存儲庫。模擬DbSet <TEntity>存儲庫中

資源庫看起來是這樣的:

public class ChangeLogRepository : Repository<ChangeLog>, IChangeLogRepository 
{ 
    public ChangeLogRepository(IDbContext context, long tenantId) : base(context, tenantId) 
    { 
    } 
} 

的基類:

public class Repository<TEntity> where TEntity : class { 
    protected readonly IDbContext Context; 
    protected DbSet<TEntity> Entities { get; set; } 
    public long TenantId { get; set; } 

    protected Repository(IDbContext context, long tenant) 
    { 
     Context = context; 
     TenantId = tenant; 
     Entities = Context.Set<TEntity>(); 
    } 
    public List<TEntity> GetAll() 
    { 
     return Entities.ToList(); 
    } 
    //.. 
} 

最後但並非最不重要的,測試類:

[TestClass] 
public class ChangeLogRepository_Test 
{ 
    private ChangeLogRepository repository; 
    private List<ChangeLog> allTestData; 

    [TestInitialize] 
    public void TestInitialize() 
    { 
     var dbContext = new Mock<IDbContext>(); 
     allTestData = new List<ChangeLog>() { 
      new ChangeLog { Id = 10, EntityName = "User",PropertyName = "UserName",PrimaryKeyValue = 1,OldValue = "Max",NewValue = "Moritz",DateChanged = DateTime.Now,FieldType = ChangeLogFieldType.Default }, 
      new ChangeLog { Id = 10, EntityName = "User",PropertyName = "CreatedAt",PrimaryKeyValue =2,OldValue = "15/06/2017",NewValue = "15/06/2017",DateChanged = DateTime.Now,FieldType = ChangeLogFieldType.Date }, 
      new ChangeLog { Id = 10, EntityName = "Role",PropertyName = "RoleName",PrimaryKeyValue = 56,OldValue = "Admin",NewValue = "Administrator",DateChanged = DateTime.Now,FieldType = ChangeLogFieldType.Default }, 
     }; 
     var changelogs = MockDbSet(allTestData); 
     dbContext.Setup(m => m.Set<ChangeLog>()).Returns(() => changelogs); 
     repository = new ChangeLogRepository(dbContext.Object, 10); 
    } 

    [TestMethod] 
    public void Setup_Test() 
    { 
     Assert.AreEqual(repository.GetAll(), allTestData); 
    } 
    private static DbSet<T> MockDbSet<T>(IEnumerable<T> list) where T : class, new() 
    { 
     IQueryable<T> queryableList = list.AsQueryable(); 
     Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>(); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(queryableList.GetEnumerator()); 
     return dbSetMock.Object; 
    } 
} 

如果我運行它,則測試失敗,因爲getAll()方法會返回null。它接縫,該物業'實體'沒有被嘲弄的Set()方法正確初始化。

當我在存儲庫構造函數 中設置斷點並檢查實體屬性時,在「表達式>值>結果視圖」下出現三個條目。在第一個結果視圖下,有一個「枚舉不會產生結果」消息,兩行使用?在它(Visual Studio 2017)中。

如何正確嘲笑存儲庫中的實體?我究竟做錯了什麼?

回答

2

我完全基於原始問題中提供的示例重新創建測試,但無法重現null問題。模擬模塊返回了一個人口稠密的集合,就像它配置的那樣。

比較兩個集合時出現問題但是,

Assert.AreEqual(repository.GetAll(), allTestData); 

他們不認爲是相等的。預計,因爲ToList將創建一個新的列表,這顯然是用作模擬數據源的原始列表的不同參考。

使用CollectionAssert.AreEquivalent代替

[TestMethod] 
public void Setup_Test() { 
    var actual = repository.GetAll(); 
    CollectionAssert.AreEquivalent(allTestData, actual); 
} 

比較兩個集合和測試通過。