2015-07-10 222 views
20

我正在嘗試爲測試目的設置模擬DbSet。我在這裏使用了教程,http://www.loganfranken.com/blog/517/mocking-dbset-queries-in-ef6/並略微修改了它,所以每次調用GetEnumerator都會返回一個新的枚舉器(我遇到的另一個問題)。但是,我很難將項目添加到DbSet。如何將項目添加到模擬DbSet(使用Moq)

輸出是preCount = 3 postCount = 3.但是,我期望它是預計數= 3 postCount = 4.任何幫助非常感謝。

static void Main(string[] args) 
    { 
     Debug.WriteLine("hello debug"); 

     List<string> stringList = new List<string> 
     { 
      "a", "b", "c" 
     }; 

     DbSet<string> myDbSet = GetQueryableMockDbSet(stringList); 
     int preCount = myDbSet.Count(); 
     myDbSet.Add("d"); 
     int postCount = myDbSet.Count(); 
     Debug.WriteLine("preCount = " + preCount + " postCount = " + postCount); 
    } 

    private static DbSet<T> GetQueryableMockDbSet<T>(List<T> sourceList) where T : class 
    { 
     var queryable = sourceList.AsQueryable(); 

     var dbSet = new Mock<DbSet<T>>(); 
     dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider); 
     dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression); 
     dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType); 
     dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator()); 

     return dbSet.Object; 
    } 
+0

很不錯的方法來封裝創建dbSet。 你有沒有更新過這個來支持異步查詢? –

+0

至少目前與.net核心1.0,這將回答異步問題:[如何使用實體框架核心模擬異步存儲庫](https://stackoverflow.com/questions/40476233/how-to-mock -an-async-repository-with-entity-framework-core) –

回答

53

myDbSet是不是真正落實DbSet而是一個模擬的,這意味着它是,它需要設置你所需要的所有方法。 Add也不例外,所以它需要設置爲做你需要的東西,否則它什麼也不做。

添加如下內容,當myDbSet.Add("d");被調用時,'d'被添加到列表中並且可以稍後返回。

dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => sourceList.Add(s)); 

完整代碼

private static DbSet<T> GetQueryableMockDbSet<T>(List<T> sourceList) where T : class 
{ 
    var queryable = sourceList.AsQueryable(); 

    var dbSet = new Mock<DbSet<T>>(); 
    dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider); 
    dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression); 
    dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType); 
    dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator()); 
    dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => sourceList.Add(s)); 

    return dbSet.Object; 
} 

輸出

hello debug 
preCount = 3 postCount = 4 
+0

問題是,當你添加一些東西到數據庫時,你將不得不手動設置導航屬性,而這個模擬會保存對象。我想知道是否有辦法模仿EF的這種行爲。 – tocqueville

+2

嘲笑EF的一點是因爲它不希望將數據庫帶入您的測試。擁有快速運行的分區化測試只測試特定的API會更好。另一種選擇是https://msdn.microsoft.com/en-us/data/dn314431.aspx「內存雙」,但是,內存雙打和嘲笑本質上是一回事。 – andrew

+0

你有更新這個以支持異步查詢的機會嗎? –