2. Integrazione Spring/NHibernate
Il framework Spring fornisce classi di utilità per lavorare con il framework NHibernate. L'uso di queste classi semplifica la scrittura del codice per l'accesso ai dati da un sistema di gestione di database. Si consideri la seguente architettura multistrato:
![]() |
Nelle sezioni seguenti, costruiremo un livello [DAO] utilizzando [Spring / NHibernate] commentando il codice di una soluzione funzionante. Non tenteremo di coprire tutte le possibili configurazioni o utilizzi del framework [Spring / NHibernate]. I lettori possono adattare la soluzione proposta alle proprie esigenze con l'aiuto della documentazione di Spring.NET [Spring.NET | Homepage ] (dicembre 2011).
2.1. Il livello di accesso ai dati [DAO]
![]() |
Il database è il database MySQL [dbpam_nhibernate] già presentato nella sezione 1.2. Il livello [DAO] implementa la seguente interfaccia 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. Il progetto Visual Studio C# per il livello [DAO]
Il progetto Visual Studio per il livello [dao] è il seguente:
![]() |
- in [1], il progetto nel suo complesso
- la cartella [pam] contiene le classi del progetto e la configurazione delle entità NHibernate
- i file [App.config] e [Dao.xml] configurano il framework Spring/NHibernate. Dovremo descrivere il contenuto di questi due file.
- in [2], le varie classi del progetto
- nella cartella [entities], troviamo le entità NHibernate studiate nel progetto precedente (vedi pagina 14)
- Nella cartella [service], troviamo l'interfaccia [IPamDao] e la sua implementazione con il framework Spring/NHibernate [PamDaoSpringNHibernate].
- La cartella [tests] contiene i test per l'interfaccia [IPamDao].
- In [3], i riferimenti del progetto. L'integrazione Spring/NHibernate richiede nuove DLL [4].
Nei riferimenti del progetto [3], troviamo le seguenti DLL:
- NHibernate: per l'ORM NHibernate
- MySql.Data: il driver ADO.NET per il DBMS MySQL 5
- Spring.Core: per il framework Spring, che gestisce l'integrazione dei livelli
- log4net: una libreria di logging
- nunit.framework: una libreria per i test unitari
- Spring.Aop, Spring.Data e Spring.Data.NHibernate32: forniscono il supporto per Spring/NHibernate.
Ci assicureremo che la proprietà "Copia in locale" per tutte queste DLL sia impostata su True.
2.1.2. Configurazione del progetto C#
Il progetto è strutturato come segue:
![]() |
- In [1], il nome dell'assembly del progetto è [pam-dao-spring-nhibernate]. Questo nome compare in vari file di configurazione del progetto.
2.1.3. Entità nel livello [dao]
![]() |
Le entità (oggetti) necessarie per il livello [dao] sono state raccolte nella cartella [entities] [1] del progetto. Queste entità sono le stesse del progetto precedente (vedere la sezione 1.3.2), con un'unica differenza riscontrabile nei file di configurazione di NHibernate. Prendiamo, ad esempio, il file [Employee.hbm.xml]:
- in [2], il file è configurato per essere incluso nell'assembly del progetto
Il suo contenuto è il seguente:
<?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>
- riga 3: l'attributo assembly indica che il file [Employe.hbm.xml] si trova nell'assembly [pam-dao-spring-nhibernate]
Inoltre, nella cartella [entities], troviamo una classe di eccezione utilizzata dal progetto:
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;
}
}
}
La classe [PamException] è stata derivata dalla classe [Exception] (riga 4) per aggiungere un codice di errore (riga 7).
2.1.4. Configurazione Spring / NHibernate
Torniamo al progetto Visual C#:
![]() |
- In [1], i file [App.config] e [Dao.xml] configurano l'integrazione Spring / NHibernate
2.1.4.1. Il file [ App.config]
Il file [App.config] è il seguente:
<?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>
Il file [App.config] sopra riportato configura Spring (righe 5–9, 15–22), log4net (riga 10, righe 28–53), ma non NHibernate. Gli oggetti Spring non sono configurati in [App.config] ma nel file [Dao.xml] (riga 20). La configurazione di Spring/NHibernate, che consiste nel dichiarare specifici oggetti Spring, si troverà quindi in questo file.
2.1.4.2. Il file [Dao.xml]
Il file [Dao.xml], che contiene gli oggetti gestiti da Spring, è il seguente:
<?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>
- Le righe 11–13 configurano la connessione al database [dbpam_nhibernate]. Esse includono:
- il provider ADO.NET necessario per la connessione, in questo caso il provider DBMS MySQL. Ciò richiede che la DLL [Mysql.Data] sia inclusa nei riferimenti del progetto.
- la stringa di connessione al database (server, nome del database, proprietario della connessione e password)
- Le righe 15–29 configurano la SessionFactory di NHibernate, l'oggetto utilizzato per ottenere le sessioni NHibernate. Si noti che tutte le operazioni sul database vengono eseguite all'interno di una sessione NHibernate. Alla riga 15, possiamo vedere che la SessionFactory è implementata dalla classe Spring.Data.NHibernate.LocalSessionFactoryObject, presente nella DLL Spring.Data.NHibernate32.
- Riga 16: la proprietà DbProvider imposta i parametri di connessione al database (provider ADO.NET e stringa di connessione). In questo caso, questa proprietà fa riferimento all'oggetto DbProvider definito in precedenza alle righe 11–13.
- Righe 17-20: specificano l'elenco degli assembly contenenti i file [*.hbm.xml] che configurano le entità gestite da NHibernate. La riga 19 indica che questi file si trovano nell'assembly del progetto. Si noti che questo nome si trova nelle proprietà del progetto C#. Si noti inoltre che tutti i file [*.hbm.xml] sono stati configurati per essere inclusi nell'assembly del progetto.
- Righe 22–27: Proprietà specifiche di NHibernate.
- Riga 24: il dialetto SQL utilizzato sarà MySQL
- Riga 25: L'SQL generato da NHibernate non apparirà nei log della console. Impostare questa proprietà su true consente di visualizzare le istruzioni SQL generate da NHibernate. Questo può aiutare a capire, ad esempio, perché un'applicazione è lenta quando accede al database.
- Riga 28: Impostare la proprietà ExposeTransactionAwareSessionFactory su true farà sì che Spring gestisca le annotazioni di gestione delle transazioni presenti nel codice C#. Torneremo su questo argomento quando scriveremo la classe che implementa il livello [DAO].
- Le righe 32–36 definiscono il gestore delle transazioni. Anche in questo caso, si tratta di una classe Spring proveniente dalla DLL Spring.Data.NHibernate32. Questo gestore richiede i parametri di connessione al database (riga 34) e la SessionFactory di NHibernate (riga 35).
- Le righe 39–43 definiscono le proprietà della classe HibernateTemplate, che è anch'essa una classe Spring. Questa classe verrà utilizzata come classe di utilità nella classe che implementa il livello [DAO]. Essa facilita le interazioni con gli oggetti NHibernate. Questa classe presenta alcune proprietà che devono essere inizializzate:
- riga 40: la SessionFactory di NHibernate
- riga 41: la proprietà TemplateFlushMode imposta la modalità di sincronizzazione del contesto di persistenza NHibernate con il database. La modalità Auto garantisce che la sincronizzazione avvenga:
- alla fine di una transazione
- prima di un'operazione SELECT
- riga 42: le query HQL (Hibernate Query Language) verranno memorizzate nella cache. Ciò può comportare un aumento delle prestazioni.
- Le righe 46–48 definiscono la classe di implementazione per il livello [dao]
- riga 46: il livello [dao] sarà implementato dalla classe [PamdaoSpringNHibernate] nella DLL [pam-dao-spring-nhibernate]. Dopo l'istanziazione della classe, verrà eseguito immediatamente il metodo init della classe. Quando il contenitore Spring viene chiuso, verrà eseguito il metodo destroy della classe.
- Riga 47: la classe [PamDaoSpringNHibernate] avrà una proprietà HibernateTemplate che verrà inizializzata con la proprietà HibernateTemplate della riga 39.
2.1.5. Implementazione del livello [dao]
2.1.5.1. Lo scheletro della classe di implementazione
L'interfaccia [IPamDao] è la seguente:
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();
}
}
- Riga 1: Importiamo lo spazio dei nomi per le entità nel livello [dao].
- Riga 3: Il livello [dao] si trova nello spazio dei nomi [Pam.Dao.Service]. Gli elementi nello spazio dei nomi [Pam.Dao.Entities] possono essere creati in più istanze. Gli elementi nello spazio dei nomi [Pam.Dao.Service] vengono creati come singola istanza (singleton). Questo è ciò che ha giustificato la scelta dei nomi degli spazi dei nomi.
- Riga 4: L'interfaccia si chiama [IPamDao]. Definisce tre metodi:
- Riga 6: [GetAllIdentitesEmployes] restituisce un array di oggetti di tipo [Employe] che rappresenta l'elenco dei fornitori di servizi di assistenza all'infanzia in un formato semplificato (cognome, nome, SS).
- Riga 8: [GetEmploye] restituisce un oggetto [Employe]: il dipendente con il numero di previdenza sociale passato come parametro al metodo, insieme ai benefici associati al suo livello retributivo.
- Riga 10, [GetCotisations] restituisce l'oggetto [Cotisations], che incapsula le aliquote dei vari contributi previdenziali da detrarre dallo stipendio lordo.
Lo scheletro della classe di implementazione per questa interfaccia utilizzando Spring/NHibernate potrebbe essere il seguente:
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;
}
}
}
- Riga 9: La classe [PamDaoSpringNHibernate] implementa correttamente l'interfaccia del livello [dao] [IPamDao]. Deriva inoltre dalla classe Spring [HibernateDaoSupport]. Questa classe dispone di una proprietà [HibernateTemplate] che viene inizializzata dalla configurazione Spring impostata (riga 2 di seguito):
<object id="pamdao" type="Pam.Dao.Service.PamDaoSpringNHibernate, pam-dao-spring-nhibernate" init-method="init" destroy-method="destroy">
<property name="HibernateTemplate" ref="HibernateTemplate"/>
</object>
- Nella riga 1 sopra, vediamo che la definizione dell'oggetto [pamdao] specifica che i metodi init e destroy della classe [PamDaoSpringNHibernate] devono essere eseguiti in momenti specifici. Questi due metodi sono effettivamente presenti nella classe alle righe 16 e 21.
- Righe 15, 34: annotazioni che assicurano che il metodo annotato venga eseguito all'interno di una transazione. L'attributo ReadOnly=true indica che la transazione è di sola lettura. Il metodo eseguito all'interno della transazione può generare un'eccezione. In questo caso, Spring esegue automaticamente il rollback della transazione. Questa annotazione elimina la necessità di gestire una transazione all'interno del metodo.
- Riga 16: il metodo init viene eseguito da Spring immediatamente dopo l'istanziazione della classe. Vedremo che il suo scopo è quello di inizializzare i campi privati alle righe 11 e 12. Verrà eseguito all'interno di una transazione (riga 15).
- I metodi dell'interfaccia [IPamDao] sono implementati alle righe 28, 35 e 40.
- Righe 28–30: il metodo [GetAllIdentitesEmployes] restituisce semplicemente l'attributo della riga 12, che è stato inizializzato dal metodo init.
- Righe 40–42: il metodo [GetCotisations] restituisce semplicemente l'attributo della riga 11, che è stato inizializzato dal metodo init.
2.1.5.2. Metodi utili della classe HibernateTemplate
Utilizzeremo i seguenti metodi della classe HibernateTemplate:
esegue la query HQL e restituisce un elenco di oggetti di tipo T | |
esegue una query HQL parametrizzata da ?. I valori di questi parametri sono forniti dall'array di oggetti. | |
restituisce tutte le entità di tipo T |
Esistono altri metodi utili che non avremo modo di utilizzare, che consentono di recuperare, salvare, aggiornare ed eliminare entità:
Aggiunge l'entità di tipo T con l'ID della chiave primaria alla sessione NHibernate. | |
Inserisce (INSERT) o aggiorna (UPDATE) l'oggetto entità a seconda che abbia una chiave primaria (UPDATE) o meno (INSERT). L'assenza di una chiave primaria può essere configurata utilizzando l'attributo `unsaved-values` nel file di configurazione dell'entità. Dopo l'operazione `SaveOrUpdate`, l'oggetto entità si trova nella sessione NHibernate. | |
Rimuove l'oggetto entità dalla sessione NHibernate. |
2.1.5.3. Implementazione del metodo init
Il metodo init della classe [PamDaoSpringNHibernate] è, per impostazione predefinita, il metodo eseguito dopo che Spring ha istanziato la classe. Il suo scopo è quello di memorizzare nella cache locale le identità semplificate dei dipendenti (cognome, nome, codice fiscale) e le aliquote contributive. Il codice potrebbe essere il seguente.
[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);
}
}
- riga 5: Viene eseguita una query HQL. Recupera i campi SS, LastName e FirstName da tutte le entità Employee. Restituisce un elenco di oggetti. Se avessimo richiesto l'intero record Employee utilizzando "select e from Employee e", avremmo recuperato un elenco di oggetti di tipo Employee.
- righe 7–12: questo elenco di oggetti viene copiato in un array di oggetti di tipo Employee.
- Riga 14: recuperiamo l'elenco di tutte le entità di tipo Contributions. Sappiamo che questo elenco ha un solo elemento. Recuperiamo quindi il primo elemento dell'elenco per ottenere le aliquote contributive.
- Le righe 7 e 14 inizializzano i due campi privati della classe.
2.1.5.4. Implementazione del metodo GetEmployee
Il metodo GetEmployee deve restituire l'entità Employee con un determinato SSN. Il suo codice potrebbe essere il seguente:
[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];
}
}
- riga 6: recupera l'elenco dei dipendenti con un determinato numero di previdenza sociale
- riga 12: normalmente, se il dipendente esiste, dovremmo ottenere un elenco con un solo elemento
- riga 14: in caso contrario, genera un'eccezione
- riga 16: in tal caso, restituisce il primo dipendente dell'elenco
2.2. Test del livello [DAO]
2.2.1. Il progetto Visual Studio
Il progetto Visual Studio è già stato presentato. Come promemoria:
![]() |
- in [1], il progetto nel suo complesso
- in [2], le varie classi del progetto. La cartella [tests] contiene un test da console [Main.cs] e un test unitario [NUnit.cs].
- in [3], il programma [Main.cs] viene compilato.
![]() |
- in [4], il file [NUnit.cs] non viene generato.
- Il progetto è un'applicazione console. La classe in esecuzione è quella specificata in [5], ovvero la classe nel file [Main.cs].
2.2.2. Il programma di test da console [Main.cs]
Il programma di test [Main.cs] viene eseguito nella seguente architettura:
![]() |
È responsabile del test dei metodi dell'interfaccia [IPamDao]. Un esempio di base potrebbe essere il seguente:
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();
}
}
}
- Riga 11: chiediamo a Spring un riferimento al livello [dao].
- righe 13–15: test del metodo [GetAllEmployeeIDs] dell'interfaccia [IPamDao]
- riga 18: test del metodo [GetEmploye] dell'interfaccia [IPamDao]
- riga 21: test del metodo [GetCotisations] dell'interfaccia [IPamDao]
Spring, NHibernate e log4net sono configurati tramite il file [ App.config] descritto nella Sezione 2.1.4.1.
L'esecuzione del programma con il database descritto nella sezione 1.2 produce il seguente output della console:
- righe 1-2: i 2 dipendenti di tipo [Employee] con solo le informazioni [SS, Cognome, Nome]
- riga 4: il dipendente di tipo [Employee] con numero di previdenza sociale [254104940426058]
- riga 5: aliquote contributive
2.2.3. Test unitari con NUnit
Passeremo ora a un test unitario con NUnit. Il progetto Visual Studio per il livello [dao] si evolverà come segue:
![]() |
- in [1], il programma di test [NUnit.cs]
- in [2,3], il progetto genererà una DLL denominata [pam-dao-spring-nhibernate.dll]
- in [4], il riferimento alla DLL del framework NUnit: [nunit.framework.dll]
- in [5], la classe [Main.cs] non sarà inclusa nella DLL [pam-dao-spring-nhibernate]
- in [6], la classe [NUnit.cs] sarà inclusa nella DLL [pam-dao-spring-nhibernate]
La classe di test NUnit è la seguente:
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);
}
}
}
- riga 11: la classe ha l'attributo [TestFixture], che la rende una classe di test [NUnit].
- riga 12: la classe deriva dalla classe di utilità AssertionHelper del framework NUnit (a partire dalla versione 2.4.6).
- riga 14: il campo privato [pamDao] è un'istanza dell'interfaccia che fornisce l'accesso al livello [dao]. Si noti che il tipo di questo campo è un'interfaccia, non una classe. Ciò significa che l'istanza [pamDao] rende accessibili solo i metodi, in particolare quelli dell'interfaccia [IPamDao].
- I metodi testati nella classe sono quelli con l'attributo [Test]. Per tutti questi metodi, il processo di test è il seguente:
- Il metodo con l'attributo [SetUp] viene eseguito per primo. Viene utilizzato per preparare le risorse (connessioni di rete, connessioni al database, ecc.) necessarie per il test.
- Quindi viene eseguito il metodo da testare
- e infine viene eseguito il metodo con l'attributo [TearDown]. Viene generalmente utilizzato per liberare le risorse allocate dal metodo con l'attributo [SetUp].
- Nel nostro test, non ci sono risorse da allocare prima di ogni test e da deallocare in seguito. Pertanto, non abbiamo bisogno di metodi con gli attributi [SetUp] e [TearDown]. Per l'esempio, abbiamo incluso, alle righe 23–26, un metodo con l'attributo [SetUp].
- Righe 17-20: il costruttore della classe inizializza il campo privato [pamDao] utilizzando Spring e [App.config].
- Righe 29–32: Test del metodo [GetAllIdentitesEmployes]
- Righe 35–42: Test del metodo [GetCotisations]
- Righe 45–53: Test del metodo [GetEmploye]
- Righe 56–65: Testare il metodo [GetEmploye] quando si verifica un'eccezione.
La generazione del progetto crea la DLL [pam-dao-spring-nhibernate.dll] nella cartella [bin/Release]:
![]() |
Carichiamo la DLL [pam-dao-spring-nhibernate.dll] utilizzando lo strumento [NUnit-Gui], versione 2.5, ed eseguiamo i test:

Come si vede sopra, i test hanno avuto esito positivo.
2.2.4. Generazione della DLL del livello [dao] con
Una volta che la classe [PamDaoNHibernate] è stata scritta e testata, genereremo la DLL del livello [dao] come segue:
![]() |
- [1], i programmi di test sono esclusi dall'assembly del progetto
- [2,3], configurazione del progetto
- [4], generazione del progetto
- La DLL viene generata nella cartella [bin/Release] [5].











