2. Spring/NHibernate 集成
Spring 框架提供了用于与 NHibernate 框架交互的工具类。使用这些类可以更轻松地编写从数据库管理系统中访问数据的代码。请考虑以下多层架构:
![]() |
在接下来的章节中,我们将通过注释一个可运行的解决方案的代码,使用 [Spring / NHibernate] 构建 [DAO] 层。我们不会试图涵盖 [Spring / NHibernate] 框架的所有可能配置或用法。读者可以借助 Spring.NET 文档 [Spring.NET | 主页](2011 年 12 月)将提出的解决方案调整为适合自身需求。
2.1. [DAO] 数据访问层
![]() |
数据库是第 1.2 节中已介绍的 MySQL 数据库 [dbpam_nhibernate]。[DAO] 层实现了以下 C# 接口:
using Pam.Dao.Entites;
namespace Pam.Dao.Service {
public interface IPamDao {
// list of all employee identities
Employe[] GetAllIdentitesEmployes();
// an individual employee with benefits
Employe GetEmploye(string ss);
// list of all contributions
Cotisations GetCotisations();
}
}
2.1.1. [DAO] 层的 Visual Studio C# 项目
[DAO] 层的 Visual Studio 项目如下:
![]() |
- 在 [1] 中,整个项目
- [pam] 文件夹包含项目类以及 NHibernate 实体配置
- [App.config] 和 [Dao.xml] 文件用于配置 Spring/NHibernate 框架。我们将需要详细说明这两个文件的内容。
- 在 [2] 中,项目的各类类
- 在 [entities] 文件夹中,我们可以找到上一个项目中研究过的 NHibernate 实体(参见第 14 页)
- 在 [service] 文件夹中,我们可以找到 [IPamDao] 接口及其在 Spring/NHibernate 框架下的实现 [PamDaoSpringNHibernate]。
- [tests] 文件夹包含针对 [IPamDao] 接口的测试。
- 在 [3] 中,是项目的引用。Spring/NHibernate 集成需要新的 DLL 文件 [4]。
在项目引用 [3] 中,我们发现以下 DLL:
- NHibernate:用于 NHibernate ORM
- MySql.Data:用于 MySQL 5 数据库管理系统(DBMS)的 ADO.NET 驱动程序
- Spring.Core:用于 Spring 框架,负责各层面的集成
- log4net:日志记录库
- nunit.framework:一个单元测试库
- Spring.Aop、Spring.Data 和 Spring.Data.NHibernate32:提供 Spring/NHibernate 支持。
我们将确保所有这些 DLL 的“复制到本地”属性都设置为 True。
2.1.2. 配置 C# 项目
该项目的配置如下:
![]() |
- 在[1]中,项目程序集名称为[pam-dao-spring-nhibernate]。该名称出现在各种项目配置文件中。
2.1.3. [dao] 层中的实体
![]() |
[dao] 层所需的实体(对象)已汇总在项目的 [entities] 文件夹 [1] 中。这些实体与前一个项目中的实体相同(参见第 1.3.2 节),但 NHibernate 配置文件中存在一个差异。以 [Employee.hbm.xml] 文件为例:
- 在 [2] 中,该文件被配置为包含在项目程序集内
其内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="Pam.Dao.Entites" assembly="pam-dao-spring-nhibernate">
<class name="Employe" table="EMPLOYES">
<id name="Id" column="ID">
<generator class="native" />
</id>
<version name="Version" column="VERSION"/>
<property name="SS" column="SS" length="15" not-null="true" unique="true"/>
<property name="Nom" column="NOM" length="30" not-null="true"/>
<property name="Prenom" column="PRENOM" length="20" not-null="true"/>
<property name="Adresse" column="ADRESSE" length="50" not-null="true" />
<property name="Ville" column="VILLE" length="30" not-null="true"/>
<property name="CodePostal" column="CP" length="5" not-null="true"/>
<many-to-one name="Indemnites" column="INDEMNITE_ID" cascade="all" lazy="false"/>
</class>
</hibernate-mapping>
- 第 3 行:assembly 属性表示文件 [Employe.hbm.xml] 将位于程序集 [pam-dao-spring-nhibernate] 中
此外,在 [entities] 文件夹中,我们发现了一个该项目使用的异常类:
using System;
namespace Pam.Dao.Entites {
public class PamException : Exception {
// the error code
public int Code { get; set; }
// manufacturers
public PamException() {
}
public PamException(int Code)
: base() {
this.Code = Code;
}
public PamException(string message, int Code)
: base(message) {
this.Code = Code;
}
public PamException(string message, Exception ex, int Code)
: base(message, ex) {
this.Code = Code;
}
}
}
[PamException] 类是从 [Exception] 类派生而来的(第 4 行),用于添加错误代码(第 7 行)。
2.1.4. Spring / NHibernate 配置
让我们回到 Visual C# 项目:
![]() |
- 在 [1] 中,[App.config] 和 [Dao.xml] 文件配置了 Spring / NHibernate 的集成
2.1.4.1. [ App.config] 文件
[App.config] 文件内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- configuration sections -->
<configSections>
<sectionGroup name="spring">
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
</sectionGroup>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<!-- spring configuration -->
<spring>
<parsers>
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
</parsers>
<context>
<resource uri="Dao.xml" />
</context>
</spring>
<!-- This section contains the log4net configuration settings -->
<!-- NOTE IMPORTANTE: logs are not active by default. They must be activated by program
avec l'instruction log4net.Config.XmlConfigurator.Configure();
! -->
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %logger - %message%newline" />
</layout>
</appender>
<!-- Set default logging level to DEBUG -->
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
<!-- Set logging for Spring . Logger names in Spring correspond to the namespace -->
<logger name="Spring">
<level value="INFO" />
</logger>
<logger name="Spring.Data">
<level value="DEBUG" />
</logger>
<logger name="NHibernate">
<level value="DEBUG" />
</logger>
</log4net>
</configuration>
上面的 [App.config] 文件配置了 Spring(第 5–9 行、第 15–22 行)和 log4net(第 10 行、第 28–53 行),但未配置 NHibernate。Spring 对象不在 [App.config] 中配置,而是在 [Dao.xml] 文件中配置(第 20 行)。 因此,包含特定 Spring 对象声明的 Spring/NHibernate 配置将位于此文件中。
2.1.4.2. [Dao.xml] 文件
包含 Spring 管理对象的 [Dao.xml] 文件如下:
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:db="http://www.springframework.net/database">
<!-- Referenced by main application context configuration file -->
<description>
Application Spring / NHibernate
</description>
<!-- Database and NHibernate Configuration -->
<db:provider id="DbProvider"
provider="MySql.Data.MySqlClient"
connectionString="Server=localhost;Database=dbpam_nhibernate;Uid=root;Pwd=;"/>
<object id="NHibernateSessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate32">
<property name="DbProvider" ref="DbProvider"/>
<property name="MappingAssemblies">
<list>
<value>pam-dao-spring-nhibernate</value>
</list>
</property>
<property name="HibernateProperties">
<dictionary>
<entry key="dialect" value="NHibernate.Dialect.MySQL5Dialect"/>
<entry key="hibernate.show_sql" value="false"/>
</dictionary>
</property>
<property name="ExposeTransactionAwareSessionFactory" value="true" />
</object>
<!-- transaction manager -->
<object id="transactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate32">
<property name="DbProvider" ref="DbProvider"/>
<property name="SessionFactory" ref="NHibernateSessionFactory"/>
</object>
<!-- Hibernate Template -->
<object id="HibernateTemplate" type="Spring.Data.NHibernate.Generic.HibernateTemplate">
<property name="SessionFactory" ref="NHibernateSessionFactory" />
<property name="TemplateFlushMode" value="Auto" />
<property name="CacheQueries" value="true" />
</object>
<!-- Data Access Objects -->
<object id="pamdao" type="Pam.Dao.Service.PamDaoSpringNHibernate, pam-dao-spring-nhibernate" init-method="init" destroy-method="destroy">
<property name="HibernateTemplate" ref="HibernateTemplate"/>
</object>
</objects>
- 第 11–13 行配置了与 [dbpam_nhibernate] 数据库的连接。其中包括:
- 连接所需的 ADO.NET 提供程序,本例中为 MySQL 数据库管理系统 (DBMS) 提供程序。这要求在项目引用中包含 [Mysql.Data] DLL。
- 数据库连接字符串(服务器、数据库名称、连接所有者和密码)
- 第 15–29 行配置了 NHibernate SessionFactory,该对象用于获取 NHibernate 会话。请注意,所有数据库操作均在 NHibernate 会话内执行。在第 15 行中,我们可以看到 SessionFactory 由 Spring 类 Spring.Data.NHibernate.LocalSessionFactoryObject 实现,该类位于 Spring.Data.NHibernate32 DLL 中。
- 第 16 行:DbProvider 属性用于设置数据库连接参数(ADO.NET 提供程序和连接字符串)。此处,该属性引用了之前在第 11–13 行定义的 DbProvider 对象。
- 第 17–20 行:指定包含 [*.hbm.xml] 文件的程序集列表,这些文件用于配置由 NHibernate 管理的实体。第 19 行表明这些文件将位于项目程序集中。请注意,此名称可在 C# 项目属性中找到。另请注意,所有 [*.hbm.xml] 文件均已配置为包含在项目程序集中。
- 第 22–27 行:NHibernate 专用的属性。
- 第 24 行:将使用的 SQL 方言为 MySQL
- 第 25 行:NHibernate 生成的 SQL 语句不会出现在控制台日志中。将此属性设置为 true 可让您查看 NHibernate 生成的 SQL 语句。这有助于您理解,例如,应用程序在访问数据库时为何运行缓慢。
- 第 28 行:将 ExposeTransactionAwareSessionFactory 属性设置为 true 将导致 Spring 管理 C# 代码中发现的事务管理注解。我们在编写实现 [DAO] 层的类时将再次讨论这一点。
- 第 32–36 行定义了事务管理器。同样,该管理器是来自 Spring.Data.NHibernate32 DLL 的 Spring 类。该管理器需要数据库连接参数(第 34 行)以及 NHibernate SessionFactory(第 35 行)。
- 第 39–43 行定义了 HibernateTemplate 类的属性,该类也是 Spring 类。该类将在实现 [DAO] 层的类中作为辅助类使用,用于简化与 NHibernate 对象的交互。该类包含一些必须初始化的属性:
- 第 40 行:NHibernate 的 SessionFactory
- 第 41 行:TemplateFlushMode 属性用于设置 NHibernate 持久化上下文与数据库的同步模式。Auto 模式确保同步操作发生在:
- 在事务结束时
- 在执行 SELECT 操作之前
- 第 42 行:HQL(Hibernate 查询语言)查询将被缓存。这可以带来性能提升。
- 第 46–48 行定义了 [dao] 层的实现类
- 第 46 行:[dao] 层将由 [pam-dao-spring-nhibernate] DLL 中的 [PamdaoSpringNHibernate] 类实现。该类实例化后,其 init 方法将立即执行。当 Spring 容器关闭时,该类的 destroy 方法将被执行。
- 第 47 行:[PamDaoSpringNHibernate] 类将拥有一个 HibernateTemplate 属性,该属性将使用第 39 行中的 HibernateTemplate 属性进行初始化。
2.1.5. [dao] 层的实现
2.1.5.1. 实现类的骨架
[IPamDao] 接口如下:
using Pam.Dao.Entites;
namespace Pam.Dao.Service {
public interface IPamDao {
// list of all employee identities
Employe[] GetAllIdentitesEmployes();
// an individual employee with benefits
Employe GetEmploye(string ss);
// list of all contributions
Cotisations GetCotisations();
}
}
- 第 1 行:我们导入了 [dao] 层中实体的命名空间。
- 第 3 行:[dao] 层位于 [Pam.Dao.Service] 命名空间中。[Pam.Dao.Entities] 命名空间中的元素可以创建多个实例,而 [Pam.Dao.Service] 命名空间中的元素则作为单例(singleton)创建。这正是命名空间命名选择的依据。
- 第 4 行:接口命名为 [IPamDao]。它定义了三个方法:
- 第 6 行:[GetAllIdentitesEmployes] 返回一个 [Employe] 类型的对象数组,以简化格式(姓、名、社保号)表示托儿服务提供者的列表。
- 第 8 行:[GetEmploye] 返回一个 [Employe] 对象:该对象对应的是作为方法参数传入的社会保险号所属的员工,并包含与其薪级相关的福利。
- 第 10 行,[GetCotisations] 返回 [Cotisations] 对象,该对象封装了从毛薪中扣除的各项社会保障缴费率。
使用 Spring/NHibernate 实现此接口的类骨架可能如下所示:
using System;
using System.Collections;
using System.Collections.Generic;
using Pam.Dao.Entites;
using Spring.Data.NHibernate.Generic.Support;
using Spring.Transaction.Interceptor;
namespace Pam.Dao.Service {
public class PamDaoSpringNHibernate : HibernateDaoSupport, IPamDao {
// private fields
private Cotisations cotisations;
private Employe[] employes;
// init
[Transaction(ReadOnly = true)]
public void init() {
...
}
// delete object
public void destroy() {
if (HibernateTemplate.SessionFactory != null) {
HibernateTemplate.SessionFactory.Close();
}
}
// list of all employee identities
public Employe[] GetAllIdentitesEmployes() {
return employes;
}
// an individual employee with benefits
[Transaction(ReadOnly = true)]
public Employe GetEmploye(string ss) {
....
}
// list of contributions
public Cotisations GetCotisations() {
return cotisations;
}
}
}
- 第 9 行:[PamDaoSpringNHibernate] 类正确实现了 [dao] 层接口 [IPamDao]。它还继承自 Spring 类 [HibernateDaoSupport]。该类有一个 [HibernateTemplate] 属性,该属性由下方第 2 行设置的 Spring 配置进行初始化:
<object id="pamdao" type="Pam.Dao.Service.PamDaoSpringNHibernate, pam-dao-spring-nhibernate" init-method="init" destroy-method="destroy">
<property name="HibernateTemplate" ref="HibernateTemplate"/>
</object>
- 在上文第 1 行中,我们可以看到 [pamdao] 对象的定义指定了 [PamDaoSpringNHibernate] 类的 init 和 destroy 方法必须在特定时间执行。这两个方法确实存在于该类的第 16 行和第 21 行。
- 第 15 行、第 34 行:这些注解确保被注解的方法将在事务内执行。ReadOnly=true 属性表示该事务为只读事务。在事务内执行的方法可能会抛出异常。在这种情况下,Spring 会自动回滚事务。此注解消除了在方法内部管理事务的必要性。
- 第 16 行:类实例化后,Spring 会立即执行 init 方法。我们将看到,其目的是初始化第 11 行和第 12 行的私有字段。该方法将在事务中运行(第 15 行)。
- [IPamDao] 接口的方法在第 28、35 和 40 行中实现。
- 第 28–30 行:[GetAllIdentitiesEmployees] 方法仅返回第 12 行定义的属性,该属性由 init 方法初始化。
- 第 40–42 行:[GetCotisations] 方法仅返回第 11 行中的属性,该属性由 init 方法初始化。
2.1.5.2. HibernateTemplate 类的常用方法
我们将使用 HibernateTemplate 类的以下方法:
执行 HQL 查询并返回类型为 T 的对象列表 | |
执行一个由 ? 参数化的 HQL 查询。这些参数的值由对象数组提供。 | |
返回所有类型为 T 的实体 |
还有其他一些我们可能没有机会用到的有用方法,它们允许您检索、保存、更新和删除实体:
将主键为 id 的类型为 T 的实体添加到 NHibernate 会话中。 | |
根据实体对象是否具有主键(有主键则执行 UPDATE,无主键则执行 INSERT),分别对该实体进行插入(INSERT)或更新(UPDATE)操作。是否存在主键可通过实体配置文件中的 `unsaved-values` 属性进行配置。执行 `SaveOrUpdate` 操作后,该实体对象将处于 NHibernate 会话中。 | |
将实体对象从 NHibernate 会话中移除。 |
2.1.5.3. init 方法的实现
根据配置,[PamDaoSpringNHibernate] 类的 init 方法是在 Spring 实例化该类后执行的方法。其目的是将简化的员工身份信息(姓氏、名字、社会安全号码)和缴费率缓存到本地。其代码如下所示。
[Transaction(ReadOnly = true)]
public void init() {
try {
// retrieve the simplified list of employees
IList<object[]> lignes = HibernateTemplate.Find<object[]>("select e.SS,e.Nom,e.Prenom from Employe e");
// we put it in a table
employes = new Employe[lignes.Count];
int i = 0;
foreach (object[] ligne in lignes) {
employes[i] = new Employe() { SS = ligne[0].ToString(), Nom = ligne[1].ToString(), Prenom = ligne[2].ToString() };
i++;
}
// we put the contribution rates in a
cotisations = (HibernateTemplate.LoadAll<Cotisations>())[0];
} catch (Exception ex) {
// on transforme l'exception
throw new PamException(string.Format("Erreur d'accès à la BD : [{0}]", ex.ToString()), 43);
}
}
- 第 5 行:执行了一个 HQL 查询。该查询从所有 Employee 实体中检索 SS、LastName 和 FirstName 字段,并返回一个对象列表。如果我们使用 "select e from Employee e" 查询整个 Employee 记录,则会返回一个 Employee 类型的对象列表。
- 第 7–12 行:将该对象列表复制到一个 Employee 类型的对象数组中。
- 第 14 行:我们获取所有类型为 Contributions 的实体列表。我们知道该列表仅包含一个元素。因此,我们获取列表的第一个元素以获取贡献率。
- 第 7 行和第 14 行初始化了该类的两个私有字段。
2.1.5.4. GetEmployee 方法的实现
GetEmployee 方法必须返回具有给定 SSN 的 Employee 实体。其代码如下所示:
[Transaction(ReadOnly = true)]
public Employe GetEmploye(string ss) {
IList<Employe> employés = null;
try {
// request
employés = HibernateTemplate.Find<Employe>("select e from Employe e where e.SS=?", new object[]{ss});
} catch (Exception ex) {
// on transforme l'exception
throw new PamException(string.Format("Erreur d'accès à la BD lors de la demande de l'employé de n° ss [{0}] : [{1}]", ss, ex.ToString()), 41);
}
// has an employee been recovered?
if (employés.Count == 0) {
// we report the fact
throw new PamException(string.Format("L'employé de n° ss [{0}] n'existe pas", ss), 42);
} else {
return employés[0];
}
}
- 第 6 行:检索具有给定社保号的员工列表
- 第 12 行:通常情况下,如果该员工存在,我们应得到一个包含一个元素的列表
- 第 14 行:如果不是,则抛出异常
- 第 16 行:如果是,则返回列表中的第一个员工
2.2. [DAO] 层测试
2.2.1. Visual Studio 项目
Visual Studio 项目已介绍过。在此重申:
![]() |
- 在 [1] 中,展示了整个项目
- 在 [2] 中,展示了该项目的各个类。[tests] 文件夹包含一个控制台测试 [Main.cs] 和一个单元测试 [NUnit.cs]。
- 在 [3] 中,编译程序 [Main.cs]。
![]() |
- 在 [4] 中,文件 [NUnit.cs] 未生成。
- 该项目是一个控制台应用程序。正在执行的类是 [5] 中指定的类,即 [Main.cs] 文件中的类。
2.2.2. 控制台测试程序 [Main.cs]
测试程序 [Main.cs] 在以下架构下运行:
![]() |
该程序负责测试 [IPamDao] 接口的方法。一个基本示例如下:
using System;
using Pam.Dao.Entites;
using Pam.Dao.Service;
using Spring.Context.Support;
namespace Pam.Dao.Tests {
public class MainPamDaoTests {
public static void Main() {
try {
// layer instantiation [dao]
IPamDao pamDao = (IPamDao)ContextRegistry.GetContext().GetObject("pamdao");
// list of employee identities
foreach (Employe Employe in pamDao.GetAllIdentitesEmployes()) {
Console.WriteLine(Employe.ToString());
}
// an employee with benefits
Console.WriteLine("------------------------------------");
Console.WriteLine(pamDao.GetEmploye("254104940426058"));
Console.WriteLine("------------------------------------");
// list of contributions
Cotisations cotisations = pamDao.GetCotisations();
Console.WriteLine(cotisations.ToString());
} catch (Exception ex) {
// exception display
Console.WriteLine(ex.ToString());
}
//break
Console.ReadLine();
}
}
}
- 第 11 行:我们向 Spring 请求 [dao] 层的引用。
- 第 13–15 行:测试 [IPamDao] 接口的 [GetAllEmployeeIDs] 方法
- 第 18 行:测试 [IPamDao] 接口的 [GetEmployee] 方法
- 第 21 行:测试 [IPamDao] 接口的 [GetCotisations] 方法
Spring、NHibernate 和 log4net 通过第 2.1.4.1 节中讨论的 [ App.config] 文件进行配置。
使用第 1.2 节所述的数据库运行程序,将产生以下控制台输出:
- 第1-2行:2名类型为[Employee]的员工,仅包含[SS, 姓, 名]信息
- 第4行:类型为[Employee]、社会保险号为[254104940426058]的员工
- 第 5 行:缴费率
2.2.3. 使用 NUnit 进行单元测试
接下来我们将进行 NUnit 单元测试。[dao] 层的 Visual Studio 项目将演变为如下结构:
![]() |
- 在 [1] 中,测试程序 [NUnit.cs]
- 在 [2,3] 中,项目将生成一个名为 [pam-dao-spring-nhibernate.dll] 的 DLL
- 在 [4] 中,对 NUnit 框架 DLL 的引用:[nunit.framework.dll]
- 在 [5] 中,[Main.cs] 类将不会被包含在 [pam-dao-spring-nhibernate] DLL 中
- 在 [6] 中,[NUnit.cs] 类将被包含在 [pam-dao-spring-nhibernate] DLL 中
NUnit 测试类如下:
using System.Collections;
using NUnit.Framework;
using Pam.Dao.Service;
using Pam.Dao.Entites;
using Spring.Objects.Factory.Xml;
using Spring.Core.IO;
using Spring.Context.Support;
namespace Pam.Dao.Tests {
[TestFixture]
public class NunitPamDao : AssertionHelper {
// the [dao] layer to be tested
private IPamDao pamDao = null;
// manufacturer
public NunitPamDao() {
// layer instantiation [dao]
pamDao = (IPamDao)ContextRegistry.GetContext().GetObject("pamdao");
}
// init
[SetUp]
public void Init() {
}
[Test]
public void GetAllIdentitesEmployes() {
// audit no. of employees
Expect(2, EqualTo(pamDao.GetAllIdentitesEmployes().Length));
}
[Test]
public void GetCotisations() {
// checking contribution rates
Cotisations cotisations = pamDao.GetCotisations();
Expect(3.49, EqualTo(cotisations.CsgRds).Within(1E-06));
Expect(6.15, EqualTo(cotisations.Csgd).Within(1E-06));
Expect(9.39, EqualTo(cotisations.Secu).Within(1E-06));
Expect(7.88, EqualTo(cotisations.Retraite).Within(1E-06));
}
[Test]
public void GetEmployeIdemnites() {
// individual verification
Employe employe1 = pamDao.GetEmploye("254104940426058");
Employe employe2 = pamDao.GetEmploye("260124402111742");
Expect("Jouveinal", EqualTo(employe1.Nom));
Expect(2.1, EqualTo(employe1.Indemnites.BaseHeure).Within(1E-06));
Expect("Laverti", EqualTo(employe2.Nom));
Expect(1.93, EqualTo(employe2.Indemnites.BaseHeure).Within(1E-06));
}
[Test]
public void GetEmployeIdemnites2() {
// non-existent individual verification
bool erreur = false;
try {
Employe employe1 = pamDao.GetEmploye("xx");
} catch {
erreur = true;
}
Expect(erreur, True);
}
}
}
- 第 11 行:该类带有 [TestFixture] 属性,这使其成为 [NUnit] 测试类。
- 第 12 行:该类继承自 NUnit 框架(从 2.4.6 版本开始)的 AssertionHelper 工具类。
- 第 14 行:私有字段 [pamDao] 是提供对 [dao] 层访问权限的接口的实例。请注意,该字段的类型是接口,而非类。这意味着 [pamDao] 实例仅提供方法的访问权限——具体而言,即 [IPamDao] 接口中的方法。
- 该类中被测试的方法是带有 [Test] 属性的方法。对于所有这些方法,测试过程如下:
- 首先执行带有 [SetUp] 属性的方法。该方法用于准备测试所需的资源(网络连接、数据库连接等)。
- 然后执行待测试的方法
- 最后,执行带有 [TearDown] 属性的方法。该方法通常用于释放由带有 [SetUp] 属性的方法所分配的资源。
- 在我们的测试中,每个测试之前无需分配资源,测试后也无需释放资源。因此,我们不需要带有 [SetUp] 和 [TearDown] 属性的方法。为了示例,我们在第 23–26 行中包含了一个带有 [SetUp] 属性的方法。
- 第 17–20 行:类构造函数使用 Spring 和 [App.config] 初始化私有字段 [pamDao]。
- 第 29–32 行:测试 [GetAllIdentitiesEmployees] 方法
- 第 35–42 行:测试 [GetCotisations] 方法
- 第 45–53 行:测试 [GetEmploye] 方法
- 第 56–65 行:测试 [GetEmploye] 方法在发生异常时的行为。
项目生成会在 [bin/Release] 文件夹中创建 DLL 文件 [pam-dao-spring-nhibernate.dll]:
![]() |
我们使用 [NUnit-Gui] 工具(版本 2.5)加载 DLL [pam-dao-spring-nhibernate.dll],并运行测试:

如上所示,测试已成功通过。
2.2.4. 使用 生成[dao]层DLL
在编写并测试完 [PamDaoNHibernate] 类后,我们将按以下步骤生成 [dao] 层 DLL:
![]() |
- [1],测试程序被排除在项目程序集之外
- [2,3],项目配置
- [4],项目生成
- 生成的 DLL 位于 [bin/Release] 文件夹中 [5]。











