2013-02-25 70 views
2

我有一個NHibernate的攔截器,它覆蓋Instanciate方法,並執行以下操作:如何單元測試NHibernate的攔截器

  • 如果要被實例化的類繼承的某些基類,返回一個CastleDynamicProxy
  • 否則只是將這個類別設置爲無效

雖然這聽起來很容易(而且已經工作),但如果我能用單元測試證明它的功能,我仍然感覺更好。

這裏是攔截代碼:

public override object Instantiate(string entityTypeName, EntityMode entityMode, object id) 
    { 
     // Type resolution across Assembly borders 
     Type type = TypeFinder.FindType(entityTypeName); 

     if (type == null) 
     { 
      throw new Exception(string.Format("",entityTypeName)); 
     } 

     bool isViewModel = (typeof(ViewModelBase).IsAssignableFrom(type)); 

     if (entityMode == EntityMode.Poco && isViewModel) 
     { 
      var instance = ProxyFactory.CreateProxy(type); 
      SessionFactory.GetClassMetadata(entityTypeName).SetIdentifier(instance, id, entityMode); 
      return instance; 
     } 
     return base.Instantiate(entityTypeName, entityMode, id); 
    } 

我能成功地測試我的代理生成代碼,但base.Instantiate始終返回null。 這裏是我的測試代碼(正如你看到的,我甚至增加了一個真正的數據庫,公正的情況下攔截器需要一個有效的會話):

private FluentConfiguration PrepareDataBase() 
    { 
     string connectionString = @"Data Source=test.sdf;"; 
     SqlCeEngine en = new SqlCeEngine(connectionString); 
     en.CreateDatabase(); 

     FluentConfiguration fc = Fluently.Configure().Database(MsSqlCeConfiguration.Standard 
                   .ConnectionString(c => c.Is(connectionString)) 
                   .ShowSql()) 
            .Mappings(x => x.FluentMappings.AddFromAssemblyOf<ViewModel>()); 

     new SchemaExport(fc.BuildConfiguration()).Create(true, true); 
     return fc; 
    } 

    [TestMethod] 
    [DeploymentItem("System.Data.SqlServerCe.dll")] 
    public void Test_Instantiate_WithNonViewModelBasedPoco_ReturnsInstance() 
    { 
     TypeFinder.RegisterAssembly(typeof(OtherPoco).Assembly); 
     FluentConfiguration fc = PrepareDataBase(); 

     NhChangeNotificationInterceptor interceptor = new NhChangeNotificationInterceptor(); 
     ISession session = fc.BuildSessionFactory().OpenSession(interceptor); 

     string instanceType = typeof(OtherPoco).FullName; 
     object instance = interceptor.Instantiate(instanceType, EntityMode.Poco, null); 

     Assert.AreEqual(typeof(OtherPoco).FullName, instance.GetType().FullName); 
     Assert.IsFalse(typeof(ViewModelBase).IsAssignableFrom(instance.GetType())); 
    } 

我想這可能是與空標識的問題,所以我保存了記錄,並試圖增加其ID如下:

 NhChangeNotificationInterceptor interceptor = new NhChangeNotificationInterceptor(); 
     ISession session = fc.BuildSessionFactory().OpenSession(interceptor); 
     using (ITransaction trx = session.BeginTransaction()) 
     { 
      session.Save(new OtherPoco() { Id = 1 }); 
      session.Flush(); 
     } 
     string instanceType = typeof(OtherPoco).FullName; 
     object instance = interceptor.Instantiate(instanceType, EntityMode.Poco, 1); 

不會改變任何東西,雖然。 任何想法如何測試base.Instantiate

+0

是'base.Instantiate'你的代碼?如果沒有,那麼我在單元測試中看不到什麼價值。如果你想要100%的代碼覆蓋率,那麼你可以將'base.Instantiate'調用包裝成一個你可以聲稱被調用的虛擬方法。 – wal 2013-02-25 14:05:41

+0

base.Instantiate不是我的代碼。感謝您指出了這一點。 – 2013-02-25 14:11:02

回答

2

我不會爲此編寫單元測試。攔截器與NH /數據庫緊密耦合 - 最好爲此編寫集成測試。

不要試圖測試你的代碼行。相反,測試你的功能。你已經說過你的攔截器應該做什麼(「如果要實例化的類繼承一個特定的基類,返回一個CastleDynamicProxy,否則只是安裝類)」。改爲測試!如果您稍後想要使用攔截器以外的其他技術來獲得相同的結果,則不應該強制您修改測試。

因此,不要調用攔截器,直接從您的測試中進行實例化,做一些集成測試,驗證它在從數據庫中獲取數據時應該做什麼。

+0

有趣的觀點,謝謝! – 2013-02-25 15:16:53