2. Інтеграція Spring / NHibernate
Фреймворк Spring пропонує допоміжні класи для роботи з фреймворком NHibernate. Використання цих класів спрощує написання коду для доступу до даних SGBD. Розглянемо таку багаторівневу архітектуру:
![]() |
Далі ми побудуємо шар [dao] на базі [Spring / NHibernate], коментуючи код робочого рішення. Ми не будемо намагатися висвітлити всі можливості конфігурації чи використання фреймворку [Spring / Nhibernate]. Читач зможе адаптувати запропоноване рішення до своїх власних завдань, скориставшись документацією до Spring.NET та [Spring.NET | Homepage ] (грудень 2011 року).
2.1. Рівень доступу до даних [dao]
![]() |
Базою даних є база MySQL [dbpam_nhibernate], вже представлена в розділі 1.2. Рівень [dao] реалізує наступний інтерфейс C#:
using Pam.Dao.Entites;
namespace Pam.Dao.Service {
public interface IPamDao {
// перелік усіх ідентифікаційних даних працівників
Employe[] GetAllIdentitesEmployes();
// конкретний працівник із його виплатами
Employe GetEmploye(string ss);
// перелік усіх внесків
Cotisations GetCotisations();
}
}
2.1.1. Проєкт Visual Studio C# для шару [dao]
Проєкт Visual Studio для шару [dao] має такий вигляд:
![]() |
- у [1] — проект у цілому
- папка [pam] містить класи проекту, а також конфігурацію сутностей NHibernate
- файли [App.config] та [Dao.xml] налаштовують фреймворк Spring / NHibernate. Нам доведеться описати вміст цих двох файлів.
- У файлі [2] містяться різні класи проекту
- у папці [entites] ми знаходимо сутності NHibernate, розглянуті в попередньому проєкті (див. стор. 14)
- у папці [service] ми знаходимо інтерфейс [IPamDao] та його реалізацію за допомогою фреймворку Spring / NHibernate [PamDaoSpringNHibernate].
- Папка [tests] містить тести для інтерфейсу [IPamDao].
- У [3] містяться посилання на проект. Інтеграція Spring / NHibernate вимагає нових DLL та [4].
У посиланнях [3] проекту містяться такі DLL:
- NHibernate: для ORM та NHibernate
- MySql.Data: драйвер ADO.NET для SGBD MySQL 5
- 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], зібрано у папці [entites] [1] цього проєкту. Ці об’єкти є тими самими, що й у попередньому проєкті (див. розділ 1.3.2), за єдиною відмінністю, яка міститься у файлах конфігурації NHibernate. Візьмемо, наприклад, файл [Employe.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]
Крім того, у папці [entites] ми знаходимо клас винятків, який використовується проектом:
using System;
namespace Pam.Dao.Entites {
public class PamException : Exception {
// код помилки
public int Code { get; set; }
// виробники
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>
<!-- розділи налаштувань -->
<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 -->
<spring>
<parsers>
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
</parsers>
<context>
<resource uri="Dao.xml" />
</context>
</spring>
<!-- Цей розділ містить параметри конфігурації log4net -->
<!-- NOTE IMPORTANTE: журнали за замовчуванням неактивні. Їх потрібно активувати програмно
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>
<!-- Встановити рівень журналювання за замовчуванням на DEBUG -->
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
<!-- Налаштувати журналювання для Spring. Імена логерів у Spring відповідають простору імен -->
<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 / NHibernate, яка полягає у оголошенні конкретних об’єктів Spring, міститься саме в цьому файлі.
2.1.4.2. Файл [Dao.xml]
Файл [Dao.xml], що містить об’єкти, які керуються Spring, має такий вигляд:
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:db="http://www.springframework.net/database">
<!-- Посилання міститься у файлі конфігурації основного контексту додатка -->
<description>
Application Spring / NHibernate
</description>
<!-- База даних та NHibernate Конфігурація -->
<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>
<!-- менеджер транзакцій -->
<object id="transactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate32">
<property name="DbProvider" ref="DbProvider"/>
<property name="SessionFactory" ref="NHibernateSessionFactory"/>
</object>
<!-- Шаблон Hibernate -->
<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>
<!-- Об’єкти доступу до даних -->
<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, необхідний для підключення; у даному випадку це провайдер SGBD MySQL. Це означає, що у посиланнях проекту мають бути присутні DLL та [Mysql.Data].
- рядок підключення до бази даних (сервер, назва бази, власник підключення, його пароль)
- рядки 15–29 налаштовують SessionFactory з NHibernate — об’єкт, який використовується для отримання сесій NHibernate. Нагадаємо, що будь-яка операція з базою даних виконується в межах сесії NHibernate. У рядку 15 видно, що SessionFactory реалізовано класом Spring Spring.Data.NHibernate.LocalSessionFactoryObject, який міститься в DLL Spring.Data.NHibernate32.
- рядок 16: властивість DbProvider встановлює параметри підключення до бази даних (провайдер ADO.NET та рядок підключення). Тут ця властивість посилається на об’єкт DbProvider, визначений раніше у рядках 11–13.
- рядки 17–20: визначають список збірників, що містять файли [*.hbm.xml], які налаштовують об’єкти, що керуються NHibernate. Рядок 19 вказує, що ці файли будуть знайдено у збірнику проєкту. Нагадуємо, що ця назва міститься у властивостях проекту C#. Також нагадуємо, що всі файли [*.hbm.xml] було налаштовано для включення до збірки проекту.
- рядки 22–27: специфічні властивості NHibernate.
- рядок 24: діалект SQL, що використовується, буде таким самим, як у MySQL
- рядок 25: SQL, згенерований NHibernate, не з’являтиметься у журналах консолі. Встановлення цього параметра на true дозволяє дізнатися про команди SQL, відправлені NHibernate. Це може допомогти, наприклад, зрозуміти, чому додаток працює повільно під час доступу до бази даних.
- рядок 28: властивість ExposeTransactionAwareSessionFactory для true призведе до того, що Spring буде обробляти анотації управління транзакціями, які будуть знайдені в коді C#. Ми повернемося до цього, коли будемо писати клас, що реалізує шар [dao].
- Рядки 32–36 визначають менеджер транзакцій. І тут цей менеджер є класом Spring із DLL Spring.Data.NHibernate32. Цьому менеджеру потрібно знати параметри підключення до бази даних (рядок 34), а також SessionFactory та NHibernate (рядок 35).
- Рядки 39–43 визначають властивості класу HibernateTemplate, який також є класом Spring. Цей клас буде використовуватися як допоміжний клас у класі, що реалізує рівень [dao]. Він полегшує взаємодію з об’єктами NHibernate. Цей клас має певні властивості, які потрібно ініціалізувати:
- рядок 40: SessionFactory з NHibernate
- рядок 41: властивість TemplateFlushMode визначає режим синхронізації контексту збереження NHibernate з базою даних. Режим Auto забезпечує синхронізацію:
- наприкінці транзакції
- перед операцією select
- рядок 42: запити HQL (Hibernate Query Language) будуть кешовані. Це може призвести до підвищення продуктивності.
- рядки 46–48 визначають клас реалізації шару [dao]
- рядок 46: шар [dao] буде реалізовано класом [PamdaoSpringNHibernate] з DLL [pam-dao-spring-nhibernate]. Після створення екземпляра класу негайно буде виконано метод init цього класу. Під час закриття контейнера Spring буде виконано метод destroy цього класу.
- рядок 47: клас [PamDaoSpringNHibernate] матиме властивість HibernateTemplate, яка буде ініціалізована за допомогою властивості HibernateTemplate з рядка 39.
2.1.5. Реалізація шару [dao]
2.1.5.1. Скелет класу реалізації
Інтерфейс [IPamDao] має такий вигляд:
using Pam.Dao.Entites;
namespace Pam.Dao.Service {
public interface IPamDao {
// Список усіх ідентифікаторів співробітників
Employe[] GetAllIdentitesEmployes();
// конкретний працівник із його виплатами
Employe GetEmploye(string ss);
// перелік усіх внесків
Cotisations GetCotisations();
}
}
- рядок 1: імпортується простір імен сутностей шару [dao].
- рядок 3: шар [dao] знаходиться в просторі імен [Pam.Dao.Service]. Елементи простору імен [Pam.Dao.Entites] можуть створюватися у декількох екземплярах. Елементи простору імен [Pam.Dao.Service] створюються в єдиному екземплярі (singleton). Саме це зумовило вибір назв просторів імен.
- рядок 4: інтерфейс має назву [IPamDao]. Він визначає три методи:
- у рядку 6 метод [GetAllIdentitesEmployes] повертає масив об’єктів типу [Employe], який представляє список нянь у спрощеному вигляді (прізвище, ім’я, SS).
- у рядку 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 Cotisations cotisations;
private Employe[] employes;
// ініціалізація
[Transaction(ReadOnly = true)]
public void init() {
...
}
// видалення об’єкта
public void destroy() {
if (HibernateTemplate.SessionFactory != null) {
HibernateTemplate.SessionFactory.Close();
}
}
// перелік усіх ідентифікаційних даних працівників
public Employe[] GetAllIdentitesEmployes() {
return employes;
}
// конкретний працівник із його виплатами
[Transaction(ReadOnly = true)]
public Employe GetEmploye(string ss) {
....
}
// перелік внесків
public Cotisations GetCotisations() {
return cotisations;
}
}
}
- рядок 9: клас [PamDaoSpringNHibernate] правильно реалізує інтерфейс рівня [dao] [IPamDao]. Він також походить від класу Spring [HibernateDaoSupport]. Цей клас має властивість [HibernateTemplate], яка ініціалізується за допомогою виконаної конфігурації Spring (рядок 2 нижче):
<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] вказує на те, що методи init та destroy класу [PamDaoSpringNHibernate] мають виконуватися у певні моменти часу. Ці два методи дійсно присутні в класі у рядках 16 та 21.
- рядки 15, 34: анотації, які забезпечують виконання анотованого методу в рамках транзакції. Атрибут ReadOnly=true вказує, що транзакція є лише для читання. Метод, що виконується в транзакції, може викликати виняток. У цьому випадку Spring автоматично Rollback транзакцію. Ця анотація усуває необхідність керувати транзакцією всередині методу.
- рядок 16: метод init виконується Spring одразу після інстанціювання класу. Ми побачимо, що його метою є ініціалізація приватних полів у рядках 11 і 12. Він виконуватиметься в рамках транзакції (рядок 15).
- Методи інтерфейсу [IPamDao] реалізовано в рядках 28, 35 та 40.
- рядки 28–30: метод [GetAllIdentitesEmployes] лише повертає атрибут з рядка 12, ініціалізований методом init.
- рядки 40–42: метод [GetCotisations] лише повертає атрибут з рядка 11, ініціалізований методом init.
2.1.5.2. Корисні методи класу HibernateTemplate
Ми будемо використовувати такі методи класу HibernateTemplate:
виконує запит HQL і повертає список об’єктів типу T | |
виконує запит HQL, параметри якого задаються символами «?». Значення цих параметрів надаються масивом об’єктів. | |
повертає всі сутності типу T |
Існують й інші корисні методи, якими ми не матимемо нагоди скористатися, але які дозволяють знаходити, зберігати, оновлювати та видаляти об’єкти:
додає до сесії NHibernate суть типу T з первинним ключем id. | |
вставляє (INSERT) або оновлює (UPDATE) об’єкт entité залежно від того, чи має він первинний ключ (UPDATE), чи ні (INSERT). Відсутність первинного ключа можна налаштувати за допомогою атрибута unsaved-values у файлі конфігурації об’єкта. Після операції SaveOrUpdate об’єкт entité перебуває в сесії NHibernate. | |
видаляє об’єкт entité із сесії NHibernate. |
2.1.5.3. Реалізація методу init
Метод init класу [PamDaoSpringNHibernate] за налаштуванням є методом, що виконується після створення Spring екземпляра класу. Його метою є збереження в локальному кеші спрощених ідентифікаторів співробітників (прізвище, ім’я, SS) та ставок внесків. Його код може виглядати наступним чином.
[Transaction(ReadOnly = true)]
public void init() {
try {
// отримання спрощеного списку співробітників
IList<object[]> lignes = HibernateTemplate.Find<object[]>("select e.SS,e.Nom,e.Prenom from Employe e");
// вносимо його в таблицю
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++;
}
// вносимо ставки внесків до об’єкта
cotisations = (HibernateTemplate.LoadAll<Cotisations>())[0];
} catch (Exception ex) {
// перетворення винятку
throw new PamException(string.Format("Erreur d'accès à la BD : [{0}]", ex.ToString()), 43);
}
}
- рядок 5: виконується запит HQL. Він запитує поля SS, Прізвище, Ім’я для всіх сутностей Employé. Він повертає список об’єктів. Якби ми запитали повні дані про співробітника у формі «select e from Employe e», то отримали б список об’єктів типу Employe.
- рядки 7–12: цей список об’єктів копіюється в масив об’єктів типу Employe.
- рядок 14: запитується список усіх сутностей типу Cotisations. Відомо, що цей список містить лише один елемент. Тому отримується перший елемент списку, щоб отримати ставки внесків.
- Рядки 7 і 14 ініціалізують два приватні поля класу.
2.1.5.4. Реалізація методу GetEmploye
Метод GetEmploye повинен повернути об’єкт «Співробітник» із заданим номером SS. Його код може виглядати так:
[Transaction(ReadOnly = true)]
public Employe GetEmploye(string ss) {
IList<Employe> employés = null;
try {
// запит
employés = HibernateTemplate.Find<Employe>("select e from Employe e where e.SS=?", new object[]{ss});
} catch (Exception ex) {
// перетворюємо виняток
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);
}
// чи було знайдено працівника?
if (employés.Count == 0) {
// повідомляється про це
throw new PamException(string.Format("L'employé de n° ss [{0}] n'existe pas", ss), 42);
} else {
return employés[0];
}
}
- рядок 6: отримує список співробітників із заданим номером SS
- рядок 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 {
// інстанціювання шару [dao]
IPamDao pamDao = (IPamDao)ContextRegistry.GetContext().GetObject("pamdao");
// список ідентифікаційних даних співробітників
foreach (Employe Employe in pamDao.GetAllIdentitesEmployes()) {
Console.WriteLine(Employe.ToString());
}
// працівник із його виплатами
Console.WriteLine("------------------------------------");
Console.WriteLine(pamDao.GetEmploye("254104940426058"));
Console.WriteLine("------------------------------------");
// перелік внесків
Cotisations cotisations = pamDao.GetCotisations();
Console.WriteLine(cotisations.ToString());
} catch (Exception ex) {
// відображення винятку
Console.WriteLine(ex.ToString());
}
//пауза
Console.ReadLine();
}
}
}
- рядок 11: до Spring надсилається запит на отримання посилання на рівень [dao].
- рядки 13–15: тестування методу [GetAllIdentitesEmployes] інтерфейсу [IPamDao]
- рядок 18: тестування методу [GetEmploye] інтерфейсу [IPamDao]
- рядок 21: тест методу [GetCotisations] інтерфейсу [IPamDao]
Spring, NHibernate та log4net налаштовуються за допомогою файлу [App.config] , розглянутого в розділі 2.1.4.1.
Виконання з використанням бази даних, описаної в розділі 1.2, дає такий результат у консолі:
- рядки 1–2: 2 працівники типу [Employe] з єдиною інформацією [SS, Nom, Prenom]
- рядок 4: працівник типу [Employe] із номером соціального страхування [254104940426058]
- рядок 5: ставки внесків
2.2.3. Одиничні тести з NUnit
Тепер перейдемо до модульного тесту NUnit. Проєкт Visual Studio для шару [dao] зміниться наступним чином:
![]() |
- до [1], тестова програма [NUnit.cs]
- у [2,3], проект згенерує файл DLL з назвою [pam-dao-spring-nhibernate.dll]
- у [4], посилання на DLL фреймворку NUnit: [nunit.framework.dll]
- в [5], клас [Main.cs] не буде включено до DLL [pam-dao-spring-nhibernate]
- у [6] клас [NUnit.cs] буде включено до DLL [pam-dao-spring-nhibernate]
Тестовий клас 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 {
// шар [dao], що підлягає тестуванню
private IPamDao pamDao = null;
// конструктор
public NunitPamDao() {
// інстанціювання шару [dao]
pamDao = (IPamDao)ContextRegistry.GetContext().GetObject("pamdao");
}
// ініціалізація
[SetUp]
public void Init() {
}
[Test]
public void GetAllIdentitesEmployes() {
// перевірка кількості співробітників
Expect(2, EqualTo(pamDao.GetAllIdentitesEmployes().Length));
}
[Test]
public void GetCotisations() {
// перевірка ставки внесків
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() {
// перевірка осіб
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() {
// перевірка неіснуючої особи
bool erreur = false;
try {
Employe employe1 = pamDao.GetEmploye("xx");
} catch {
erreur = true;
}
Expect(erreur, True);
}
}
}
- рядок 11: клас має атрибут [TestFixture], що робить його тестовим класом [NUnit].
- рядок 12: клас походить від утилітарного класу AssertionHelper фреймворку NUnit (починаючи з версії 2.4.6).
- рядок 14: приватне поле [pamDao] є екземпляром інтерфейсу доступу до шару [dao]. Слід зауважити, що тип цього поля — це інтерфейс, а не клас. Це означає, що екземпляр [pamDao] надає доступ лише до методів інтерфейсу [IPamDao].
- У класі тестуються методи, що мають атрибут [Test]. Для всіх цих методів процес тестування відбувається наступним чином:
- спочатку виконується метод, що має атрибут [SetUp]. Він слугує для підготовки ресурсів (мережевих з’єднань, з’єднань із базами даних тощо), необхідних для тестування.
- потім виконується метод, що тестується
- і, нарешті, виконується метод з атрибутом [TearDown]. Він, як правило, слугує для звільнення ресурсів, задіяних методом з атрибутом [SetUp].
- У нашому тесті немає ресурсів, які потрібно виділяти перед кожним тестом і потім звільняти. Тому нам не потрібні методи з атрибутами [SetUp] та [TearDown]. Для прикладу ми навели у рядках 23–26 метод з атрибутом [SetUp].
- рядки 17–20: конструктор класу ініціалізує приватне поле [pamDao] за допомогою Spring та [App.config].
- рядки 29–32: тестують метод [GetAllIdentitesEmployes]
- рядки 35–42: тестують метод [GetCotisations]
- рядки 45–53: тестують метод [GetEmploye]
- рядки 56–65: тестують метод [GetEmploye] під час виникнення винятку.
Під час генерації проєкту у папці [bin/Release] створюються файли DLL та [pam-dao-spring-nhibernate.dll]:
![]() |
Завантажуємо DLL та [pam-dao-spring-nhibernate.dll] за допомогою інструменту [NUnit-Gui], версія 2.5, і виконуємо тести:

Як показано вище, тести пройшли успішно.
2.2.4. Генераці та DLL з шару [dao]
Після написання та тестування класу [PamDaoNHibernate] ми згенеруємо DLL з шару [dao] наступним чином:
![]() |
- [1], тестові програми виключаються зі збірки проекту
- [2,3], налаштування проекту
- [4], генерація проекту
- DLL генерується у папці [bin/Release] [5].











