Nhibernate测试驱动开发.docx
《Nhibernate测试驱动开发.docx》由会员分享,可在线阅读,更多相关《Nhibernate测试驱动开发.docx(52页珍藏版)》请在冰豆网上搜索。
Nhibernate测试驱动开发
Nhibernate测试驱动开发
本文约定:
1.Nhibernate简写为NHB;
2.本文例子的开发平台为win2000xp+sp2,sqlserver2000,Nhibernate0.9.1.0;
3.使用SQLServer自带的罗斯文商贸数据库(Northwind),中文版;
4.本文例子是基于测试驱动开发(TDD)的,因此建议使用NUnit2.2和Log4Net(如果你不熟悉NUnit,不要紧啊,趁此机会学习点简单的应用);
一NHB简介
NHB是基于的O/RMapping持久框架,它从基于Java的Hibernate项目移植而来。
O/RMapping就是把对象到映射关系数据库的记录,简单的说就是能实现把一个对象存储为数据表中的一条记录和由一条记录创建一个相应的对象,数据表中的数据就是对象的属性。
那么为什么要使用O/RMapping?
它与传统的DataSet/DataTable又有什么不同了?
首先是设计上的不同,当使用O/RMapping时,更多的是从对象的角度来设计程序,而把数据(对象的属性)存储的细节放在后面,可以完全采用面向对象(OO)的方式来设计,而在使用DataSet/DataTable时,它只是存放数据的对象,看起来更像一个数据表,不能直观的表达业务概念。
二NHB中主要接口的介绍
ISession
ISession是面向用户的主要接口,主要用于对象持久化,数据加载等操作,支持数据库事务,它隐藏了NHB内部复杂的实现细节,ISession由ISessionFactory创建。
ISessionFactory
ISessionFactory是NHB内部的核心类,它维护到持久机制(数据库)的连接并对它们进行管理,同时还会保存所有持久对象的映射信息。
ISessionFactory由Configuration创建,因为创建ISessionFactory的开销非常大(需要加载映射信息),所以这个对象一般使用Singleton(单例)模式。
ITransaction
ITransaction是NHB的事务处理接口,它只是简单的封装了底层的数据库事务。
事务必须由ISession来启动。
ICriteria
ICriteria是Expression(表达式)数据加载接口,Expression是一个关系表达式组合,通过它能产生SQL语句的Where部分,用户需要通过ISession来间接调用它。
IQuery
IQuery是HQL数据加载接口,HQL(HibernateQueryLanguage)是NHB专用的面向对象的数据查询语言,它与数据库的SQL有些类似,但功能更强大!
同ICriteria一样,也需要通过ISession来间接调用它。
三持久化操作
1.会话和会话工厂
要进行持久化操作,必须先取得ISession和ISessionFactory,我们用一个Sessions类来封装它们,Sessions类的属性和方法都是静态的,它有一个Factory属性,用于返回ISessionFactory,有一个GetSession方法,用于取得一个新的ISession。
测试类代码如下:
style="BORDER-RIGHT:
black1pxsolid;PADDING-RIGHT:
4px;BORDER-TOP:
black1pxsolid;PADDING-LEFT:
4px;PADDING-BOTTOM:
4px;BORDER-LEFT:
black1pxsolid;PADDING-TOP:
4px;BORDER-BOTTOM:
black1pxsolid;BACKGROUND-COLOR:
#ededed"
usingSystem;
usingNUnit.Framework;
usingNHibernate;
namespaceNHibernateTest
{
///
///SessionsFixture的摘要说明。
///
///
[TestFixture]
publicclassSessionsFixture
{
publicSessionsFixture()
{
//
//TODO:
在此处添加构造函数逻辑
//
}
[Test]//测试能否取得NHB会话工厂。
publicvoidFactoryTest()
{
ISessionFactorysf=Sessions.Factory;
Assert.IsNotNull(sf,"getsessionfactoryfail!
");
}
[Test]//测试能否取得NHB会话。
publicvoidGetSessionTest()
{
ISessions=Sessions.GetSession();
Assert.IsNotNull(s,"getsessionfail!
");
}
}
}
现在还没写Sessions类,将不能通过编译!
下面我们来实现Sessions类.
style="BORDER-RIGHT:
black1pxsolid;PADDING-RIGHT:
4px;BORDER-TOP:
black1pxsolid;PADDING-LEFT:
4px;PADDING-BOTTOM:
4px;BORDER-LEFT:
black1pxsolid;PADDING-TOP:
4px;BORDER-BOTTOM:
black1pxsolid;BACKGROUND-COLOR:
#ededed"
usingSystem;
usingNHibernate;
usingSystem.Reflection;
namespaceNHibernateTest
{
///
///Sessions的摘要说明。
///
publicclassSessions
{
privatestaticreadonlyobjectlockObj=newobject();
privatestaticISessionFactory_factory;
publicSessions()
{
//
//TODO:
在此处添加构造函数逻辑
//
}
publicstaticISessionFactoryFactory
{
get
{
if(_factory==null)
{
lock(lockObj)
{
if(_factory==null)
{
NHibernate.Cfg.Configurationcfg=newNHibernate.Cfg.Configuration();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
_factory=cfg.BuildSessionFactory();
}
}
}
return_factory;
}
}
publicstaticISessionGetSession()
{
returnFactory.OpenSession();
}
}
}
OK,现在编译可以通过了,启动NUnit并选择生成的文件NHibernateTest.exe,运行测试。
我们得到了红色的条,出错了!
原来还没有加入NHibernate的配置信息(当使用NHibernate时,需要在项目的配置文件中加入NHibernate的配置信息。
关于配置信息,在下面有说明)。
在项目的配置文件App.Config(如没有请自行创建一个)中加入以下内容.
稍做解释,下面的配置文件主要是配置了NHibernate和log4net,例如配置了NHibernate连接数据库的连接字符串;log4net把日志记到哪个文件中,本例就是"log.txt"。
每次写日志向文件中追加,而不是重写
style="BORDER-RIGHT:
black1pxsolid;PADDING-RIGHT:
4px;BORDER-TOP:
black1pxsolid;PADDING-LEFT:
4px;PADDING-BOTTOM:
4px;BORDER-LEFT:
black1pxsolid;PADDING-TOP:
4px;BORDER-BOTTOM:
black1pxsolid;BACKGROUND-COLOR:
#ededed"
xmlversion="1.0"encoding="utf-8"?
>
configSections>
key="hibernate.show_sql"
value="true"
/>
key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider"
/>
key="hibernate.dialect"
value="NHibernate.Dialect.MsSql2000Dialect"
/>
key="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver"
/>
key="hibernate.connection.connection_string"
value="Server=127.0.0.1;initialcatalog=Northwind;Userid=golinjoe;Password=2525775"
/>
nhibernate>
-%m%n"/>
layout>
appender>
root>
log4net>
configuration>
再次运行测试,就可以看见绿色的条了。
在取得会话工厂的代码中,我使用了如下代码:
if(_factory==null){
lock(lockObj){
if(_factory==null){
//buildsessionfactorycode;
}
}
}
这是一个典型的doublelock方式,用来产生线程安全的Singletion(单例)对象。
2.基本CRUD操作
在很多介绍NHB的文章,包括NHB带的测试用例中,业务对象只是做为一个数据实体存在的,它没有任何操作!
这在java中是比较典型的作法。
而我希望我们的业务对象自身就能完成基本的Create/Retrieve/Update/Delete,即CRUD操作,
在罗斯文商贸应用中,存在客户(customer)业务对象,先来为它建立一个测试用例,
style="BORDER-RIGHT:
black1pxsolid;PADDING-RIGHT:
4px;BORDER-TOP:
black1pxsolid;PADDING-LEFT:
4px;PADDING-BOTTOM:
4px;BORDER-LEFT:
black1pxsolid;PADDING-TOP:
4px;BORDER-BOTTOM:
black1pxsolid;BACKGROUND-COLOR:
#ededed"
usingSystem;
usingNHibernate;
usingNUnit.Framework;
namespaceNHibernateTest
{
///
///CustomerFixture的摘要说明。
///
[TestFixture]
publicclassCustomerFixture
{
publicCustomerFixture()
{}
[Test]//测试Customer对象的CRUD操作。
publicvoidTestCRUD()
{
Customerc=newCustomer();
c.CustomerId="test";
c.CompanyName="companyname";
c.ContactName="contactname";
c.Address="address";
c.Create();//测试insert操作,
Customerc2=newCustomer(c.CustomerId);//测试retrieve操作.
Assert.AreEqual(c2.CompanyName,"companyname","savecompanynamefail!
");
c2.CompanyName="updatename";
c2.Update();//测试update操作.
Customerc3=newCustomer(c.CustomerId);
Assert.AreEqual(c3.CompanyName,"updatename","updatecompanynamefail!
");
c3.Delete();//测试delete操作.
}
}
}
接下来创建Customer业务类:
style="BORDER-RIGHT:
black1pxsolid;PADDING-RIGHT:
4px;BORDER-TOP:
black1pxsolid;PADDING-LEFT:
4px;PADDING-BOTTOM:
4px;BORDER-LEFT:
black1pxsolid;PADDING-TOP:
4px;BORDER-BOTTOM:
black1pxsolid;BACKGROUND-COLOR:
#ededed"
usingSystem;
namespaceNHibernateTest
{
///
///Customer的摘要说明。
///
publicclassCustomer:
BizObject
{
publicCustomer(){}
publicCustomer(stringexistingId):
base(existingId){}
#regionpersistentproperties.
privatestring_customerId=string.Empty;
privatestring_companyName=string.Empty;
privatestring_contactName=string.Empty;
privatestring_contactTitle=string.Empty;
privatestring_address=string.Empty;
privatestring_city=string.Empty;
privatestring_region=string.Empty;
privatestring_postalCode=string.Empty;
privatestring_country=string.Empty;
privatestring_phone=string.Empty;
privatestring_fax=string.Empty;
publicstringCustomerId
{
get{return_customerId;}
set{_customerId=value;}
}
publicstringCompanyName
{
get{return_companyName;}
set{_companyName=value;}
}
publicstringContactName
{
get{return_contactName;}
set{_contactName=value;}
}
publicstringContactTitle
{
get{return_contactTitle;}
set{_contactTitle=value;}
}
publicstringAddress
{
get{return_address;}
set{_address=value;}
}
publicstringCity
{
get{return_city;}
set{_city=value;}
}
publicstringRegion
{
get{return_region;}
set{_region=value;}
}
publicstringPostalCode
{
get{return_postalCode;}
set{_postalCode=value;}
}
publicstringCountry
{
get{return_country;}
set{_country=value;}
}
publicstringPhone
{
get{return_phone;}
set{_phone=value;}
}
publicstringFax
{
get{return_fax;}
set{_fax=value;}
}
#endregion
}
}
在Customer类中,没有实现CRUD操作,这些操作在业务对象基类BizObject中实现,代码如下:
style="BORDER-RIGHT:
black1pxsolid;PADDING-RIGHT:
4px;BORDER-TOP:
black1pxsolid;PADDING-LEFT:
4px;PADDING-BOTTOM:
4px;BORDER-LEFT:
black1pxsolid;PADDING-TOP:
4px;BORDER-BOTTOM:
black1pxsolid;BACKGROUND-COLOR:
#ededed"
usingSystem;
namespaceNHibernateTest
{
///
///BizObject的摘要说明。
///
publicclassBizObject
{
publicBizObject(){}
publicBizObject(objectexistingId)
{
ObjectBroker.Load(this,existingId);
}
publicvirtualvoidCreate()
{
ObjectBroker.Create(this);
}
publicvirtualvoidUpdate()
{
ObjectBroker.Update(this);
}
publicvirtualvoidDelete()
{
ObjectBroker.Delete(this);
}
}
}
BizObject简单的将数据操作转发至ObjectBroker类,目的是为了降低业务层和NHB之间的耦合,以利于持久层间的移植。
style="BORDER-RIGHT:
black1pxsolid;PADDING-RIGHT:
4px;BORDER-TOP:
black1pxsolid;PADDING-LEFT:
4px;PADDING-BOTTOM:
4px;BORDER-LEFT:
bl