2009-09-24 84 views
7

我們使用生成器模式來生成測試數據。這些域對象之間有關係。我們的功能測試需要這些對象被持久化。堅持複雜的測試數據

想想這個模型:

domain model http://i34.tinypic.com/21mg1gn.png

如果我想CI的普通實例做aNew().c().build()

如果我希望它是堅持我做aNew().c().saveIn(session)

如果我想要一個具有已知BI的C實例aNew().c().with(b).build()

那麼,你有t他的想法。我的問題是,如果我想堅持一個C,它應該堅持它是B嗎?還是應該在手之前堅持下去?如果我想要一個合理的默認B,那麼呢?如果我想堅持一個D呢?它應該堅持所有A,B,C嗎?

當然,真正的系統要複雜得多(有時用循環引用)。我正在尋找堅持複雜測試數據的最佳做法。

編輯:它看起來像我碰到了語言障礙,我的母語不是英語,所以我很抱歉默默無聞。下面是詳細信息:

  • 這並不是說我想測試
  • 我想寫一個覆蓋測試,而不是一個單元測試(結果我不會嘲笑任何東西)的遺留代碼
  • 如果數據庫被擴展到一定程度(它不使用所有實體),我試圖測試的那部分軟件會工作。

PS。請不要猶豫,要求提供更多信息,因爲我一直在努力尋找可能的最佳做法。我想出的最接近的東西是:

  1. 跟蹤在建立實體時明確設置了什麼。
  2. 假設明確設置的實體已經存在,請不要堅持它們。
  3. 堅持一切(帶着自己的持久力)。

這會行得通,但是我的蜘蛛感很刺痛,我認爲我做錯了什麼,因爲測試代碼中會涉及邏輯,如果不進行測試就會非常複雜。

編輯2:我會盡量讓自己更清楚。當我編寫/運行我的單元和一些集成測試時,我沒有問題,因爲測試數據沒有被保存,它存在於內存中。

但是,當我試圖堅持我的測試數據,休眠不會讓我保存一個實體沒有它的關係。

我該如何克服這個問題?

回答

1

您需要定義域越好級聯。如果你不能測試它,你如何期望它會在真正的應用程序中執行?

例如:

A→B:誰是這種關係的主人?你想將B添加到A,還是反過來?這可以是一個實現細節,您可以同時擁有B.SetParent(A)和A.Children.Add(B),以及在A.Children.Add(B)的情況下將B的父項設置爲A的位置周圍)。如果你這樣做會發生什麼:

A a1 = new A(); 
A a2 = new A(); 
B b = new B(); 
a1.Children.Add(b); 
b.SetParent(a); 

你需要在這裏下決心。沒有一種解決方案是完美的,所以基本上個人偏好和應用程序一致性適用於此。

使用ORM可以更快地使用普通SQL(或任何其他數據源,如XML或自己的數據源)進入這些約束問題,但是如果要編寫純SQL,也需要考慮這些問題。

對不起,我沒有給你明確的答案,但對我來說,看起來你需要考慮一些(我認爲)你還沒有完成的約束。

個人而言,我喜歡在DAL中使用NHibernate時使用的存儲庫模式。我使我的存儲庫從IDisposable實現,並讓他們分別獲得一個會話。通過這種方式,您可以將「工作單元」模式應用到您的設計中。

祝你好運:) :)

3

您應該更詳細地描述您的測試設置。特別是,爲什麼做你的功能測試需要這些對象被持久?你測試實際的持久性操作嗎?或者這只是運行測試的副作用?你想加載持久化對象作爲測試的一部分嗎?

我的問題是,如果我想堅持一個C,它應該堅持它是B?還是應該在手之前堅持下去?

這將取決於你爲什麼堅持在第一位。如果您正在對持久層進行集成測試,那麼您應該只使用應用程序本身使用的邏輯。如果這只是測試的副作用,那麼您可能需要模擬持久層,等等......

+0

想象一下,這些數據已經存在於數據庫中。另一個過程(我正在測試)正在讀取這些數據。但是有時候B是相關的,我希望在創建和堅持Bs時在測試中可見。但有時它們不相關,我試圖將它們隱藏在建造者身後。 – nimcap 2009-09-24 13:09:26

+0

這對我來說沒有意義。如果數據已經在數據庫中,爲什麼(和whan)你需要堅持下去?你是什​​麼意思,「我想讓它[B]在測試中可見」?? – sleske 2009-09-24 15:08:57

0
  • 你的測試告訴你什麼?
  • 這聽起來像你測試遺留應用程序?
  • 那麼你的編程功能已經寫在你的代碼庫中,並試圖創建一個覆蓋測試?

給我們一些更多的反饋,請

1

我分開你的答案的主題。

我的問題是,如果我想堅持一個ç,應該堅持它的?如果我想堅持一個D呢?它應該堅持所有A,B,C嗎?

這完全取決於您選擇執行的域約束。例如,是C一個實體和B一個值對象?換句話說,C有自己獨特的身份和生活嗎?是B主要由其價值和其生命週期緊密耦合到其母公司C

問這些類型的問題應該有助於指導您決定何時堅持,何時以及由誰來決定。

例如,如果兩個Ç都是實體僅僅共享的關係,你可能會決定independantly堅持他們,因爲每一個可以想見,有它自己的有意義的生活和身份。如果B是一個值對象,您可能會選擇讓其父實體C控制其生命,包括創建/檢索/更新/刪除對象。這很可能包括C堅持B

還是應該堅持下手?

要回答這個問題,您可能必須繪製出您的對象依賴關係。當對象圖被保存到RDBMS時,這些依賴關係通常由外鍵約束表示。如果C無法在沒有對B的引用的情況下運行,那麼您可能希望將它們都保存在一個事務中,首先完成B以符合數據庫的外鍵約束。繼思想的線之上,如果是子實體或Ç值對象,你甚至可能Ç負責持續

如果我想要一個合理的默認B值呢?

B的創作實例可以被委派到 -Factory。無論是將此工廠邏輯作爲類(非實例)方法,構造函數實現,還是將其作爲自己的單元分開都無關緊要。關鍵是您有一個地方可以創建和配置新的B。在這個地方你會有一個新實例化對象的默認配置。

覆蓋這些類型的問題一個很好的資源是由Domain-Driven Design Eric Evans的

+0

我無法決定哪一個可以接受,另一個來得早...所以我很抱歉,我希望有一種方法可以接受多個答案 – nimcap 2009-10-05 06:19:20

1

我不知道我的理解這個問題你正在試圖解決得很好但是......怎麼樣使用序列化整個圖形的XML像XStream或谷歌的Protocol Buffers

+0

Google協議緩衝區添加爲最喜歡的 – 2010-10-01 20:48:15

0

據我所知,問題出在你的域名上(就像你繪製的那樣)。至於我認爲C與B有多對一的關係,並且數據庫是通過一個不可爲空的外鍵字段來賦值的。另一方面,從問題中的代碼我可以理解代碼中沒有完全一個規則的強制執行,並且在C實例中引用B實例的成員可以爲null。據我所知,領域模型在代碼和運行時應該始終是正確的,所以如果這個規則在代碼中被執行(例如通過在C build()方法中要求B引用),那麼你就不會有任何持久的問題 - 你可以堅持一切。

其他更骯髒的解決方案將只是在測試之前以編程方式刪除與測試混淆的所有數據庫約束,然後再恢復它們。當然,這會使數據庫完全無法運行,但是這可以通過使用諸如SQLite或SQL Server Compact Edition的集成數據庫來進行測試來解決。