1

我嘗試過使用Moq在使用DetachedCriteria類的存儲庫上單元測試方法。但是我碰到了一個問題,我無法真正模擬內部構建的內部Criteria對象。有什麼辦法模擬分離標準嗎?是否有可能單元測試依賴NHibernate Detached Criteria的方法?

測試方法

 [Test] 
     [Category("UnitTest")] 
     public void FindByNameSuccessTest() 
     {   
      //Mock hibernate here 
      var sessionMock = new Mock<ISession>(); 
      var sessionManager = new Mock<ISessionManager>(); 
      var queryMock = new Mock<IQuery>(); 
      var criteria = new Mock<ICriteria>(); 
      var sessionIMock = new Mock<NHibernate.Engine.ISessionImplementor>(); 

      var expectedRestriction = new Restriction {Id = 1, Name="Test"}; 

      //Set up expected returns 
      sessionManager.Setup(m => m.OpenSession()).Returns(sessionMock.Object); 
      sessionMock.Setup(x => x.GetSessionImplementation()).Returns(sessionIMock.Object); 

      queryMock.Setup(x => x.UniqueResult<SopRestriction>()).Returns(expectedRestriction); 

      criteria.Setup(x => x.UniqueResult()).Returns(expectedRestriction); 

      //Build repository    
      var rep = new TestRepository(sessionManager.Object); 

      //Call repostitory here to get list 
      var returnR = rep.FindByName("Test"); 


      Assert.That(returnR.Id == expectedRestriction.Id); 
     } 

倉儲類

public class TestRepository 
{ 
    protected readonly ISessionManager SessionManager; 

    public virtual ISession Session 
    { 
     get { return SessionManager.OpenSession(); } 
    } 

    public TestRepository(ISessionManager sessionManager) 
    { 
    } 


    public SopRestriction FindByName(string name) 
    { 

     var criteria = DetachedCriteria.For<Restriction>().Add<Restriction>(x => x.Name == name) 
     return criteria.GetExecutableCriteria(Session).UniqueResult<T>(); 
    } 

}

注意我用的 「NHibernate.LambdaExtensions」 和 「Castle.Facilities.NHibernateIntegration」 這裏好。任何幫助將不勝感激。

本質上,我得到返回對象的斷言空引用異常。因此我假定我沒有正確地連接標準。但我不認爲我可以這樣做,因爲標準是在我的資源庫內創建的分離標準的私有字段!

回答

5

老實說,我放棄嘗試單元測試任何觸摸數據庫的東西很久以前。

在一個內存中創建一個Sqlite數據庫並運行實際測試變得非常容易。或者,如果您希望將它們運行在真實的數據庫上,那麼只需將它們移動到您的集成測試中,只有在您簽入源代碼管理時纔會運行它們。

+0

我不是在談觸摸數據庫。我正在測試存儲庫類。確保他們實際上訪問正確的方法。我使用Sqlite單獨映射測試。我想你誤解了我的問題。我嘲笑nhibernate沒有測試實際的數據庫本身。 – 2010-06-11 15:16:53

+0

我同意你的意見,但它不是問題的答案。 – 2010-06-11 15:43:23

+0

但爲什麼模擬出NHibernate?爲什麼不直接打真正的數據庫?你應該小心過度關注如何完成某些事情,這會導致超出規範的測試氣味。你應該擔心的是,當我使用我的存儲庫時,我會得到預期的結果。 – 2010-06-14 18:13:23

1

我認爲你錯過了在這種情況下使用嘲笑的觀點。要嘲笑什麼方法

public SopRestriction FindByName(string name) 
{ 
    ... 
} 

,那麼你可以回到你想要的任何類型的SopRestriction,而不用擔心它的查詢NHibernate的事實。

因爲你永遠不會獲得任何價值,所以無意模擬任何類型的數據上下文。

最簡單的方法是從TestRepository中提取一個接口,就像ITestRepository一樣,然後讓依賴圖的其餘部分依賴於ITestRepository,並且您可以在單元測試中輕鬆地模擬庫本身。

追問:關於你提到想驗證你的資料庫什麼,我會建議在所有NHibernate的具體用法包裝成不具有任何類型的參數或者返回是NHibernate的方法本身的內部方法調用響應具體的,那麼你可以嘲笑這些方法,只是期望他們的工作。這就是爲什麼在這個階段單元測試不太有價值,因爲你沒有多少收穫。用你說的話我不會嘲笑他們,但會讓他們完全接觸數據庫或做他們需要做的事情的「集成」測試。即使TDD純粹主義者會說他們是集成測試,我仍然認爲這些都是單元測試。

+0

當然,我可以模擬一個服務或另一個具有實例化ITestRepository屬性的圖案化類。不過,我想測試SopRepository以查看某些方法是否被調用不實際檢索值。所以我認爲你也正在回答另一個問題。 – 2010-06-12 08:02:20