2009-08-04 41 views
2

以下是關於這篇文章的一些背景信息。您可以直接跳過,如果你喜歡這樣的問題:筆者認爲,「當使用NHibernate我們一般只需要測試三件事SQLite單元測試NHibernate生成級聯關係

在這個優秀的文章(http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx):
1)屬性依然存在,
2)級聯按預期工作 3)查詢返回正確的結果 - ),其映射完成&正確的(隱含的)

我的看法是,他接着說,SQLite的可以而且應該是單位測試工具的選擇做以上所有的事情。應該指出,作者似乎是更多的經驗之一有經驗的和熟練的NHib開發人員,儘管他在文章中沒有明確地說出這一點,但他後來在後面提出一個問題,即域可以並且應該處理SQLite的一些缺點。

問題:

你怎麼使用SQLite測試級聯關係,特別是考慮到它不檢查外鍵約束。如何測試模型以確保外鍵約束不會成爲數據庫問題。

這裏是一些單元測試,我想出了測試級聯行爲。該模型只是一個部門,可以有零到許多職員,級聯設置爲NONE。

[Test] 
    public void CascadeSaveIsNone_NewDepartmentWithFetchedStaff_CanSaveDepartment() 
    { 
     _newDept.AddStaff(_fetchedStaff); 
     Assert.That(_newDept.IsTransient(), Is.True); 

     _reposDept.SaveOrUpdate(_newDept); 
     _reposDept.DbContext.CommitChanges(); 

     Assert.That(_newDept.IsTransient(), Is.False); 
    } 

    [Test] 
    public void CascadeSaveIsNone_NewDepartmentWithFetchedStaff_CannotSaveNewStaff() 
    { 
     _newDept.AddStaff(_newStaff); 
     Assert.That(_newDept.IsTransient(), Is.True); 
     Assert.That(_newStaff.IsTransient(), Is.True); 

     _reposDept.SaveOrUpdate(_newDept); 
     _reposDept.DbContext.CommitChanges(); 

     Assert.That(_newDept.IsTransient(), Is.False); 
     Assert.That(_newStaff.IsTransient(), Is.True); 
    } 

    [Test] 
    public void CascadeDeleteIsNone_FetchedDepartmentWithFetchedStaff_Error() 
    { 
     _fetchedDept.AddStaff(_fetchedStaff); 
     _reposDept.SaveOrUpdate(_fetchedDept); 
     _reposStaff.DbContext.CommitChanges(); 

     _reposDept.Delete(_fetchedDept); 
     var ex = Assert.Throws<GenericADOException>(() => _reposDept.DbContext.CommitChanges()); 

     Console.WriteLine(ex.Message); 
     Assert.That(ex.Message, Text.Contains("could not delete:")); 
     Console.WriteLine(ex.InnerException.Message); 
     Assert.That(ex.InnerException.Message, Text.Contains("The DELETE statement conflicted with the REFERENCE constraint")); 
    } 

    [Test] 
    public void Nullable_NewDepartmentWithNoStaff_CanSaveDepartment() 
    { 
     Assert.That(_newDept.Staff.Count(), Is.EqualTo(0)); 

     var fetched = _reposDept.SaveOrUpdate(_newDept); 
     Assert.That(fetched.IsTransient(), Is.EqualTo(false)); 
     Assert.That(fetched.Staff.Count(), Is.EqualTo(0)); 
    } 

第三次試驗,「.._ FetchedDepartmentWithFetchedStaff_Error」的作品對SQL Server,但不是SQLite的,因爲後者不檢查外鍵約束。

這裏是測試關係的另一方;職員可以有一個部門,級聯設置爲NONE。

[Test] 
    public void CascadeSaveIsNone_NewStaffWithFetchedDepartment_CanSaveStaff() 
    { 
     _newStaff.Department = _fetchedDept; 
     _reposStaff.SaveOrUpdate(_newStaff); 
     _reposStaff.DbContext.CommitChanges(); 

     Assert.That(_newStaff.Id, Is.GreaterThan(0)); 
    } 

    [Test] 
    public void CascadeSaveIsNone_NewStaffWithNewDepartment_Error() 
    { 
     _newStaff.Department = _newDept; 
     Assert.That(_newStaff.IsTransient(), Is.True); 

     var ex = Assert.Throws<PropertyValueException>(() => _reposStaff.SaveOrUpdate(_newStaff)); 
     Console.WriteLine(ex.Message); 
     Assert.That(ex.Message, Text.Contains("not-null property references a null or transient value")); 
    } 

    [Test] 
    public void CascadeDeleteIsNone_FetchedStaffWithFetchedDepartment_DeletesTheStaff_DoesNotDeleteTheDepartment() 
    { 
     _newStaff.Department = _fetchedDept; 
     _reposStaff.SaveOrUpdate(_newStaff); 
     _reposStaff.DbContext.CommitChanges(); 

     _reposStaff.Delete(_newStaff); 
     Assert.That(_reposStaff.Get(_newStaff.Id), Is.Null); 
     Assert.That(_reposDept.Get(_fetchedDept.Id), Is.EqualTo(_fetchedDept)); 
    } 

    [Test] 
    public void NotNullable_NewStaffWithUnknownDepartment_Error() 
    { 
     var noDept = new Department("no department"); 
     _newStaff.Department = noDept; 

     var ex = Assert.Throws<PropertyValueException>(() => _reposStaff.SaveOrUpdate(_newStaff)); 
     Console.WriteLine(ex.Message); 
     Assert.That(ex.Message, Text.Contains("not-null property references a null or transient")); 
    } 

    [Test] 
    public void NotNullable_NewStaffWithNullDepartment_Error() 
    { 
     var noDept = new Department("no department"); 
     _newStaff.Department = noDept; 

     var ex = Assert.Throws<PropertyValueException>(() => _reposStaff.SaveOrUpdate(_newStaff)); 
     Console.WriteLine(ex.Message); 
     Assert.That(ex.Message, Text.Contains("not-null property references a null or transient")); 
    } 

這些測試成功針對Sql Server和SQLite。我可以信任SQLite測試嗎?這些有價值的測試?

乾杯,
Berryl

回答

3

按照我的理解文章是關於測試NHibernate的映射。在我看來,這與db相關的問題無關,而是測試你在映射中設置的nhibernate屬性。沒有必要斷言無法創建無效數據:您只需證明您的代碼創建了期望的結果並/或檢查了要檢查的內容。您可以測試級聯,級聯刪除和刪除孤立。無論你想用你在使用sqlite的測試中做到這一點。但是第三個測試試圖測試這個約束,這是沒有任何問題的。

如果你想測試你的Db約束,你應該確實使用你的生產數據庫而不是sqlite。你可以在有或沒有休眠的情況下進行,但這與你的映射無關。 另一方面,如果您真的想要使用SQLite進行Foreign Key測試的workarround,則可以嘗試使用此foreign_key_trigger_generator。我沒有嘗試,但它似乎生成之前插入觸發器,確保存在引用Pk。 也許你可以寫一個評論wheather這個工具是有用的。