2013-12-21 105 views
5

我想學習如何嘲笑我的通用知識庫,所以我可以單元測試我所有的服務。NHibernate的單元測試嘲笑/在內存數據庫

即時通訊使用流利的NHibernate來處理數據訪問和依賴性的Ninject(我不感興趣測試是)

我的倉庫界面看起來像:

public interface IRepository<TEntity> where TEntity : class 
{ 
    IQueryable<TEntity> GetAll(); 
    TEntity Get(int key); 
    void Insert(TEntity entity); 
    void Update(TEntity entity); 
    void Delete(int id); 
} 

和實際儲存庫的樣子:

public class GenerRepository<TEntity> : IRepository<TEntity>where TEntity : Entity 
{ 
    protected ISession Session{get { return NHibernateHelper.OpenSession(); }} 
    public IQueryable<TEntity> GetAll(){return Session.Query<TEntity>();} 
    public TEntity Get(int key){return Session.Get<TEntity>(key);} 
    public void Insert(TEntity entity){Session.Save(entity);} 
    public void Update(TEntity entity){Session.Update(entity);} 
    public void Delete(int id){Session.Delete(Session.Load<TEntity>(id));} 
} 

我所有的服務都做了以下操作,將創建的存儲庫加入並使用它。

我已經閱讀了很多關於如何做到這一點的文章,但沒有一篇很簡單,也沒有很好的解釋。所以建立一個測試通用知識庫或者甚至嘲笑它的任何建議。我也有興趣創建一個內存數據庫,但是如何在我的測試項目中爲流利的nhibernate設置配置,而無需在我的真實項目中編輯代碼?

是否有可能使通用存儲庫碰到Tentity列表而不是數據庫或內存數據庫。

感謝您的閱讀並期待您的建議。

+0

這是可能的。如果你這樣做,請注意LINQ提供者的方式比LINQ 2 Objects更受限制,這意味着你最終可能會針對'List '進行單元測試,並且在查詢數據庫時應用程序崩潰。 –

+0

啊,謝謝你,那麼你會如何建議我來測試一下?你能給我提供一個例子嗎? – LmC

+0

也許這是對單元測試的'純粹'(因爲它進入了一個簡單的集成測試領域),但我通常使用[內存中的SQLite數據庫](http:// ayende。COM /博客/ 3983/NHibernate的單元測試)。使用最新的NHibernate和驅動程序,我沒有一個NHibernate LINQ查詢會在SQLite上失敗(在SQL Server上工作時)。 –

回答

4

有幾個方式來實現這一點,

  1. 用於使用腳本測試設置和重新真正的數據庫使用這種方法,當數據庫發生更改時,需要花費時間和精力來創建和維護這些腳本

  2. 使用真實數據庫,並使用事務作用域進行測試(啓動事務持久化,並且做這個測試,一旦完成所有的事情都只是回滾事務),這是一個非常好的方法,我將它用於大型項目。然而,一個問題是需要花費很多時間來運行測試(我有大約3500次測試,總共需要40分鐘才能運行它們)

  3. 使用假的存儲庫(具有實體的內部列表)用於業務邏輯測試並使用實際存儲庫來驗證映射。這種方法需要額外的努力來創建和維護虛假的存儲庫。在真實存儲庫上執行的相同測試可以在假存儲庫上執行以驗證假貨正在工作。採用這種方法,測試執行會更快。

4

我的答案應該/可能是一個評論,也許。因爲我想告訴你:不要這麼做。不要浪費時間來創建從持久性返回的假數據。並且不要花費時間:從客戶端獲取數據,並將其放入內存中的某個虛擬數據庫。

您需要確定您的服務(使用存儲庫)能真正序列化/呈現真實數據。並反序列化/堅持更改。這真的需要一個真實的數據。

寧可花一些時間來創建腳本,它將填充測試數據。你可以期望在你的測試數據:做業務驗證服務的數據序列化時...

也到這裏看看:Ayende: NHibernate Unit Testing。摘錄:

當使用NHibernate我們一般只需要測試三樣東西,那 屬性依然存在,該級聯按預期工作和 查詢返回正確的結果。爲了完成所有這些,我們 通常必須與真實的數據庫交談,試圖僞造在這個級別的這些 中的任何一個都是徒勞的並且將變得非常複雜。

備註:前段時間,我們用於包裝交易Begin()Rollback()中的所有測試。這看起來不錯。但我們意識到,很多東西 - 由於缺少Flush()致電 - 未完全測試(例如設置非空)。

+0

聲音如何,我使用Ninject將我的類中的ISessioNFactory對象綁定到NHibernateHelper方法,該方法創建一個或使用已經創建的一個(this對象是靜態的)然後在我的測試中發送我的假ISessionFactory這是你的鏈接中提到如何創建? – LmC

+0

關鍵是,我們應該關心倉庫(而不是靜態會話工廠)。比方說,我們需要用'GetAll()'檢索一些數據,這些數據不可能放在帶有測試腳本的數據庫中。那麼我們應該從** IoC **中獲利。我們將繼承新的TestRepository類,並在那裏改變GetAll()的實現。我們將教* Ninject *使用這個實現(或者通過公共setter傳遞它)來進行這個特定的測試。但對於通常的測試,我們將使用「真實」**實現。 –

6

我必須同意Radim的說法,那就是在大多數情況下嘲諷nhibernate功能,而不是你想要做的事情。

除非您想測試基於您通過nhibernate檢索的數據的複雜業務邏輯,否則這非常好。

但是爲了測試您的映射,數據檢索和持久性是否正常工作,您必須針對真實數據庫進行測試。

如果您的目標是MSSQL Server,我不會使用其他類型的數據庫。相反,SQL Express具有真正服務器的所有功能。 可以選擇使用本地數據庫安裝MSSQL Express。這將允許您通過連接字符串,這將或多或少實例化MSSQL服務器的實例加載mdf文件...

我用於集成測試,它的工作真的很好。

  1. 在你的單元測試項目
  2. 創建一個數據庫文件,根據您的型號(代碼首先/ DB頭),讓NHibernate的創建方案,否則簡單的填充方式進入該數據庫文件
  3. 添加文件複製到測試設置的部署項目,以便將文件複製到測試目標目錄
  4. 生成使用複製的數據庫文件的連接字符串。 示例連接字符串:Data Source=(LocalDB)\v11.0;AttachDbFileName=[whateverthepathis]\DatabaseFileName.mdf;InitialCatalog=DatabaseName;Integrated Security=True;MultipleActiveResultSets=True
  5. 運行測試

這樣,你的測試將建立一個空數據庫,每次運行,你將有reproduceable集成測試,而不需要一個真正的服務器,你需要創建一個DB或重置每次...