2. Spring/NHibernate-Integration
Das Spring-Framework stellt Hilfsklassen für die Arbeit mit dem NHibernate-Framework bereit. Die Verwendung dieser Klassen erleichtert das Schreiben von Code für den Zugriff auf Daten aus einem Datenbankmanagementsystem. Betrachten Sie die folgende mehrschichtige Architektur:
![]() |
In den folgenden Abschnitten werden wir eine [DAO]-Schicht unter Verwendung von [Spring / NHibernate] erstellen, indem wir den Code einer funktionierenden Lösung kommentieren. Wir werden nicht versuchen, alle möglichen Konfigurationen oder Verwendungszwecke des [Spring / NHibernate]-Frameworks abzudecken. Leser können die vorgeschlagene Lösung mit Hilfe der Spring.NET-Dokumentation [Spring.NET | Homepage ] (Dezember 2011) an ihre eigenen Bedürfnisse anpassen.
2.1. Die [DAO]-Datenzugriffsschicht
![]() |
Die Datenbank ist die MySQL-Datenbank [dbpam_nhibernate], die bereits in Abschnitt 1.2 vorgestellt wurde. Die [DAO]-Schicht implementiert die folgende C#-Schnittstelle:
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. Das Visual Studio C#-Projekt für die [DAO]-Schicht
Das Visual Studio-Projekt für die [DAO]-Schicht sieht wie folgt aus:
![]() |
- in [1] das Projekt als Ganzes
- Der Ordner [pam] enthält die Projektklassen sowie die NHibernate-Entitätskonfiguration
- Die Dateien [App.config] und [Dao.xml] konfigurieren das Spring/NHibernate-Framework. Wir müssen den Inhalt dieser beiden Dateien beschreiben.
- in [2], die verschiedenen Klassen des Projekts
- Im Ordner [entities] finden wir die NHibernate-Entitäten, die im vorherigen Projekt behandelt wurden (siehe Seite 14)
- Im Ordner [service] finden wir die Schnittstelle [IPamDao] und deren Implementierung mit dem Spring/NHibernate-Framework [PamDaoSpringNHibernate].
- Der Ordner [tests] enthält die Tests für die Schnittstelle [IPamDao].
- In [3] die Projektverweise. Die Spring/NHibernate-Integration erfordert neue DLLs [4].
In den Projektreferenzen [3] finden wir die folgenden DLLs:
- NHibernate: für das NHibernate-ORM
- MySql.Data: der ADO.NET-Treiber für das MySQL 5-DBMS
- Spring.Core: für das Spring-Framework, das die Schichtenintegration übernimmt
- log4net: eine Logging-Bibliothek
- nunit.framework: eine Bibliothek für Unit-Tests
- Spring.Aop, Spring.Data und Spring.Data.NHibernate32: bieten Spring/NHibernate-Unterstützung.
Wir stellen sicher, dass die Eigenschaft „Copy to Local“ für alle diese DLLs auf „True“ gesetzt ist.
2.1.2. Konfigurieren des C#-Projekts
Das Projekt ist wie folgt aufgebaut:
![]() |
- In [1] lautet der Name der Projekt-Assembly [pam-dao-spring-nhibernate]. Dieser Name taucht in verschiedenen Projektkonfigurationsdateien auf.
2.1.3. Entitäten in der [dao]-Schicht
![]() |
Die für die [dao]-Schicht erforderlichen Entitäten (Objekte) wurden im Ordner [entities] [1] des Projekts zusammengestellt. Diese Entitäten entsprechen denen des vorherigen Projekts (siehe Abschnitt 1.3.2), mit einem Unterschied in den NHibernate-Konfigurationsdateien. Nehmen wir zum Beispiel die Datei [Employee.hbm.xml]:
- In [2] ist die Datei so konfiguriert, dass sie in die Projekt-Assembly aufgenommen wird
Ihr Inhalt lautet wie folgt:
<?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>
- Zeile 3: Das Attribut „assembly“ gibt an, dass die Datei [Employe.hbm.xml] in der Assembly [pam-dao-spring-nhibernate] zu finden ist
Außerdem finden wir im Ordner [entities] eine vom Projekt verwendete Ausnahmeklasse:
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;
}
}
}
Die Klasse [PamException] wurde von der Klasse [Exception] abgeleitet (Zeile 4), um einen Fehlercode hinzuzufügen (Zeile 7).
2.1.4. Spring-/NHibernate-Konfiguration
Kehren wir zum Visual C#-Projekt zurück:
![]() |
- In [1] konfigurieren die Dateien [App.config] und [Dao.xml] die Spring-/NHibernate-Integration
2.1.4.1. Die Datei [ App.config]
Die Datei [App.config] sieht wie folgt aus:
<?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>
Die obige [App.config]-Datei konfiguriert Spring (Zeilen 5–9, 15–22) und log4net (Zeile 10, Zeilen 28–53), jedoch nicht NHibernate. Spring-Objekte werden nicht in [App.config], sondern in der [Dao.xml]-Datei (Zeile 20) konfiguriert. Die Spring-/NHibernate-Konfiguration, die aus der Deklaration spezifischer Spring-Objekte besteht, befindet sich daher in dieser Datei.
2.1.4.2. Die Datei [Dao.xml]
Die Datei [Dao.xml], die die von Spring verwalteten Objekte enthält, sieht wie folgt aus:
<?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>
- Die Zeilen 11–13 konfigurieren die Verbindung zur Datenbank [dbpam_nhibernate]. Sie enthalten:
- den für die Verbindung erforderlichen ADO.NET-Anbieter, in diesem Fall den MySQL-DBMS-Anbieter. Dazu muss die DLL [Mysql.Data] in die Projektreferenzen aufgenommen werden.
- die Datenbankverbindungszeichenfolge (Server, Datenbankname, Verbindungseigentümer und Passwort)
- Die Zeilen 15–29 konfigurieren die NHibernate SessionFactory, das Objekt, das zum Abrufen von NHibernate-Sitzungen verwendet wird. Beachten Sie, dass alle Datenbankoperationen innerhalb einer NHibernate-Sitzung ausgeführt werden. In Zeile 15 sehen wir, dass die SessionFactory durch die Spring-Klasse Spring.Data.NHibernate.LocalSessionFactoryObject implementiert wird, die sich in der DLL Spring.Data.NHibernate32 befindet.
- Zeile 16: Die Eigenschaft DbProvider legt die Datenbankverbindungsparameter fest (ADO.NET-Anbieter und Verbindungszeichenfolge). Hier verweist diese Eigenschaft auf das zuvor in den Zeilen 11–13 definierte DbProvider-Objekt.
- Zeilen 17–20: Geben Sie die Liste der Assemblies an, die [*.hbm.xml]-Dateien enthalten, welche die von NHibernate verwalteten Entitäten konfigurieren. Zeile 19 gibt an, dass diese Dateien in der Projekt-Assembly zu finden sind. Beachten Sie, dass dieser Name in den C#-Projekteigenschaften zu finden ist. Beachten Sie außerdem, dass alle [*.hbm.xml]-Dateien so konfiguriert wurden, dass sie in die Projekt-Assembly aufgenommen werden.
- Zeilen 22–27: NHibernate-spezifische Eigenschaften.
- Zeile 24: Der verwendete SQL-Dialekt ist MySQL
- Zeile 25: Das von NHibernate generierte SQL erscheint nicht in den Konsolenprotokollen. Wenn Sie diese Eigenschaft auf „true“ setzen, können Sie die von NHibernate generierten SQL-Anweisungen sehen. Dies kann Ihnen beispielsweise helfen zu verstehen, warum eine Anwendung beim Zugriff auf die Datenbank langsam ist.
- Zeile 28: Wenn Sie die Eigenschaft „ExposeTransactionAwareSessionFactory“ auf „true“ setzen, verwaltet Spring die im C#-Code enthaltenen Annotationen zur Transaktionsverwaltung. Wir werden darauf zurückkommen, wenn wir die Klasse schreiben, die die [DAO]-Schicht implementiert.
- Die Zeilen 32–36 definieren den Transaktionsmanager. Auch dieser Manager ist eine Spring-Klasse aus der DLL „Spring.Data.NHibernate32“. Dieser Manager benötigt die Datenbankverbindungsparameter (Zeile 34) sowie die NHibernate SessionFactory (Zeile 35).
- Die Zeilen 39–43 definieren die Eigenschaften der Klasse „HibernateTemplate“, die ebenfalls eine Spring-Klasse ist. Diese Klasse wird als Hilfsklasse in der Klasse verwendet, die die [DAO]-Schicht implementiert. Sie erleichtert die Interaktion mit NHibernate-Objekten. Diese Klasse verfügt über bestimmte Eigenschaften, die initialisiert werden müssen:
- Zeile 40: die NHibernate SessionFactory
- Zeile 41: Die Eigenschaft TemplateFlushMode legt den Synchronisationsmodus des NHibernate-Persistenzkontexts mit der Datenbank fest. Der Modus „Auto“ stellt sicher, dass die Synchronisation
- am Ende einer Transaktion
- vor einer SELECT-Operation
- Zeile 42: HQL-Abfragen (Hibernate Query Language) werden zwischengespeichert. Dies kann zu einer Leistungssteigerung führen.
- Die Zeilen 46–48 definieren die Implementierungsklasse für die [dao]-Schicht
- Zeile 46: Die [dao]-Schicht wird durch die Klasse [PamdaoSpringNHibernate] in der DLL [pam-dao-spring-nhibernate] implementiert. Nach der Instanziierung der Klasse wird die init-Methode der Klasse sofort ausgeführt. Beim Schließen des Spring-Containers wird die destroy-Methode der Klasse ausgeführt.
- Zeile 47: Die Klasse [PamDaoSpringNHibernate] verfügt über eine HibernateTemplate-Eigenschaft, die mit der HibernateTemplate-Eigenschaft aus Zeile 39 initialisiert wird.
2.1.5. Implementierung der [dao]-Schicht
2.1.5.1. Das Gerüst der Implementierungsklasse
Die Schnittstelle [IPamDao] sieht wie folgt aus:
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();
}
}
- Zeile 1: Wir importieren den Namespace für Entitäten in der [dao]-Schicht.
- Zeile 3: Die [dao]-Schicht befindet sich im Namespace [Pam.Dao.Service]. Elemente im Namespace [Pam.Dao.Entities] können in mehreren Instanzen erstellt werden. Elemente im Namespace [Pam.Dao.Service] werden als einzelne Instanz (Singleton) erstellt. Dies begründete die Wahl der Namespace-Namen.
- Zeile 4: Die Schnittstelle heißt [IPamDao]. Sie definiert drei Methoden:
- Zeile 6: [GetAllIdentitesEmployes] gibt ein Array von Objekten des Typs [Employe] zurück, das die Liste der Kinderbetreuungsanbieter in einem vereinfachten Format darstellt (Nachname, Vorname, Sozialversicherungsnummer).
- Zeile 8: [GetEmploye] gibt ein [Employe]-Objekt zurück: den Mitarbeiter mit der Sozialversicherungsnummer, die als Parameter an die Methode übergeben wurde, zusammen mit den mit seiner Gehaltsstufe verbundenen Leistungen.
- Zeile 10: [GetCotisations] gibt das Objekt [Cotisations] zurück, das die Sätze der verschiedenen Sozialversicherungsbeiträge enthält, die vom Bruttogehalt abgezogen werden.
Das Grundgerüst der Implementierungsklasse für diese Schnittstelle unter Verwendung von Spring/NHibernate könnte wie folgt aussehen:
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;
}
}
}
- Zeile 9: Die Klasse [PamDaoSpringNHibernate] implementiert korrekt die Schnittstelle [IPamDao] der [dao]-Schicht. Sie leitet sich außerdem von der Spring-Klasse [HibernateDaoSupport] ab. Diese Klasse verfügt über eine Eigenschaft [HibernateTemplate], die durch die eingerichtete Spring-Konfiguration initialisiert wird (Zeile 2 unten):
<object id="pamdao" type="Pam.Dao.Service.PamDaoSpringNHibernate, pam-dao-spring-nhibernate" init-method="init" destroy-method="destroy">
<property name="HibernateTemplate" ref="HibernateTemplate"/>
</object>
- In Zeile 1 oben sehen wir, dass die Definition des Objekts [pamdao] festlegt, dass die Methoden init und destroy der Klasse [PamDaoSpringNHibernate] zu bestimmten Zeitpunkten ausgeführt werden müssen. Diese beiden Methoden sind tatsächlich in der Klasse in den Zeilen 16 und 21 vorhanden.
- Zeilen 15, 34: Annotationen, die sicherstellen, dass die annotierte Methode innerhalb einer Transaktion ausgeführt wird. Das Attribut `ReadOnly=true` gibt an, dass die Transaktion schreibgeschützt ist. Die innerhalb der Transaktion ausgeführte Methode kann eine Ausnahme auslösen. In diesem Fall rollt Spring die Transaktion automatisch zurück. Diese Annotation macht die Verwaltung einer Transaktion innerhalb der Methode überflüssig.
- Zeile 16: Die Methode `init` wird von Spring unmittelbar nach der Instanziierung der Klasse ausgeführt. Wir werden sehen, dass ihr Zweck darin besteht, die privaten Felder in den Zeilen 11 und 12 zu initialisieren. Sie wird innerhalb einer Transaktion ausgeführt (Zeile 15).
- Die Methoden der Schnittstelle [IPamDao] werden in den Zeilen 28, 35 und 40 implementiert.
- Zeilen 28–30: Die Methode [GetAllIdentitesEmployes] gibt einfach das Attribut aus Zeile 12 zurück, das durch die init-Methode initialisiert wurde.
- Zeilen 40–42: Die Methode [GetCotisations] gibt lediglich das Attribut aus Zeile 11 zurück, das von der init-Methode initialisiert wurde.
2.1.5.2. Nützliche Methoden der Klasse HibernateTemplate
Wir werden die folgenden Methoden der Klasse „HibernateTemplate“ verwenden:
führt die HQL-Abfrage aus und gibt eine Liste von Objekten vom Typ T zurück | |
führt eine HQL-Abfrage aus, die durch ? parametrisiert ist. Die Werte dieser Parameter werden durch das Objektarray bereitgestellt. | |
gibt alle Entitäten vom Typ T zurück |
Es gibt weitere nützliche Methoden, die wir hier nicht verwenden können, mit denen Sie Entitäten abrufen, speichern, aktualisieren und löschen können:
Fügt die Entität vom Typ T mit der Primärschlüssel-ID zur NHibernate-Sitzung hinzu. | |
Fügt das Entitätsobjekt ein (INSERT) oder aktualisiert es (UPDATE), je nachdem, ob es einen Primärschlüssel hat (UPDATE) oder nicht (INSERT). Das Fehlen eines Primärschlüssels kann mithilfe des Attributs `unsaved-values` in der Konfigurationsdatei der Entität konfiguriert werden. Nach der Operation `SaveOrUpdate` befindet sich das Entitätsobjekt in der NHibernate-Sitzung. | |
Entfernt das Entitätsobjekt aus der NHibernate-Sitzung. |
2.1.5.3. Implementierung der init-Methode
Die init-Methode der Klasse [PamDaoSpringNHibernate] ist laut Konfiguration die Methode, die ausgeführt wird, nachdem Spring die Klasse instanziiert hat. Ihr Zweck besteht darin, die vereinfachten Mitarbeiteridentitäten (Nachname, Vorname, Sozialversicherungsnummer) und Beitragssätze lokal zwischenzuspeichern. Der Code könnte wie folgt aussehen.
[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);
}
}
- Zeile 5: Eine HQL-Abfrage wird ausgeführt. Sie ruft die Felder SS, LastName und FirstName aus allen Employee-Entitäten ab. Sie gibt eine Liste von Objekten zurück. Hätten wir den gesamten Employee-Datensatz mit „select e from Employee e“ angefordert, hätten wir eine Liste von Objekten vom Typ Employee erhalten.
- Zeilen 7–12: Diese Liste von Objekten wird in ein Array von Objekten vom Typ „Employee“ kopiert.
- Zeile 14: Wir rufen die Liste aller Entitäten vom Typ „Contributions“ ab. Wir wissen, dass diese Liste nur ein Element enthält. Daher rufen wir das erste Element der Liste ab, um die Beitragssätze zu erhalten.
- In den Zeilen 7 und 14 werden die beiden privaten Felder der Klasse initialisiert.
2.1.5.4. Implementierung der Methode „GetEmployee“
Die Methode „GetEmployee“ muss die Entität „Employee“ mit einer bestimmten Sozialversicherungsnummer zurückgeben. Ihr Code könnte wie folgt aussehen:
[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];
}
}
- Zeile 6: Ruft die Liste der Mitarbeiter mit einer bestimmten Sozialversicherungsnummer ab
- Zeile 12: Normalerweise sollten wir, wenn der Mitarbeiter existiert, eine Liste mit einem Element erhalten
- Zeile 14: Wenn nicht, wird eine Ausnahme ausgelöst
- Zeile 16: Wenn ja, den ersten Mitarbeiter in der Liste zurückgeben
2.2. [DAO]-Schicht-Tests
2.2.1. Das Visual Studio-Projekt
Das Visual Studio-Projekt wurde bereits vorgestellt. Zur Erinnerung:
![]() |
- in [1] das Projekt als Ganzes
- in [2] die verschiedenen Klassen des Projekts. Der Ordner [tests] enthält einen Konsolentest [Main.cs] und einen Unit-Test [NUnit.cs].
- in [3] wird das Programm [Main.cs] kompiliert.
![]() |
- in [4] wird die Datei [NUnit.cs] nicht generiert.
- Das Projekt ist eine Konsolenanwendung. Die ausgeführte Klasse ist die in [5] angegebene Klasse in der Datei [Main.cs].
2.2.2. Das Konsolentestprogramm [Main.cs]
Das Testprogramm [Main.cs] läuft in der folgenden Architektur:
![]() |
Es ist für das Testen der Methoden der [IPamDao]-Schnittstelle zuständig. Ein einfaches Beispiel könnte wie folgt aussehen:
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();
}
}
}
- Zeile 11: Wir fordern von Spring eine Referenz auf die [dao]-Schicht an.
- Zeilen 13–15: Testen der Methode [GetAllEmployeeIDs] der Schnittstelle [IPamDao]
- Zeile 18: Testen der Methode [GetEmploye] der Schnittstelle [IPamDao]
- Zeile 21: Testen der Methode [GetCotisations] der Schnittstelle [IPamDao]
Spring, NHibernate und log4net werden über die in Abschnitt 2.1.4.1 beschriebene Datei [ App.config] konfiguriert.
Die Ausführung des Programms mit der in Abschnitt 1.2 beschriebenen Datenbank erzeugt die folgende Konsolenausgabe:
- Zeilen 1–2: die 2 Mitarbeiter vom Typ [Employee] mit den Informationen [SS, Nachname, Vorname]
- Zeile 4: der Mitarbeiter vom Typ [Employee] mit der Sozialversicherungsnummer [254104940426058]
- Zeile 5: Beitragssätze
2.2.3. Unit-Tests mit NUnit
Wir fahren nun mit einem NUnit-Unit-Test fort. Das Visual Studio-Projekt für die [dao]-Schicht wird sich wie folgt entwickeln:
![]() |
- in [1] das Testprogramm [NUnit.cs]
- in [2,3] generiert das Projekt eine DLL mit dem Namen [pam-dao-spring-nhibernate.dll]
- in [4] den Verweis auf die NUnit-Framework-DLL: [nunit.framework.dll]
- in [5] wird die Klasse [Main.cs] nicht in die DLL [pam-dao-spring-nhibernate] aufgenommen
- in [6] wird die Klasse [NUnit.cs] in die DLL [pam-dao-spring-nhibernate] aufgenommen
Die NUnit-Testklasse sieht wie folgt aus:
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);
}
}
}
- Zeile 11: Die Klasse verfügt über das Attribut [TestFixture], wodurch sie zu einer [NUnit]-Testklasse wird.
- Zeile 12: Die Klasse leitet sich von der Utility-Klasse „AssertionHelper“ des NUnit-Frameworks ab (ab Version 2.4.6).
- Zeile 14: Das private Feld [pamDao] ist eine Instanz der Schnittstelle, die Zugriff auf die [dao]-Schicht gewährt. Beachten Sie, dass der Typ dieses Feldes eine Schnittstelle ist, keine Klasse. Das bedeutet, dass die Instanz [pamDao] nur Methoden zugänglich macht – insbesondere diejenigen der Schnittstelle [IPamDao].
- Die in der Klasse getesteten Methoden sind diejenigen mit dem Attribut [Test]. Für alle diese Methoden läuft der Testprozess wie folgt ab:
- Zunächst wird die Methode mit dem Attribut [SetUp] ausgeführt. Sie dient dazu, die für den Test erforderlichen Ressourcen (Netzwerkverbindungen, Datenbankverbindungen usw.) vorzubereiten.
- Anschließend wird die zu testende Methode ausgeführt
- und schließlich wird die Methode mit dem Attribut [TearDown] ausgeführt. Sie dient im Allgemeinen dazu, die von der Methode mit dem Attribut [SetUp] zugewiesenen Ressourcen freizugeben.
- In unserem Test gibt es keine Ressourcen, die vor jedem Test zugewiesen und anschließend wieder freigegeben werden müssen. Daher benötigen wir keine Methoden mit den Attributen [SetUp] und [TearDown]. Für das Beispiel haben wir in den Zeilen 23–26 eine Methode mit dem Attribut [SetUp] eingefügt.
- Zeilen 17–20: Der Klassenkonstruktor initialisiert das private Feld [pamDao] mithilfe von Spring und [App.config].
- Zeilen 29–32: Testen der Methode [GetAllIdentitesEmployes]
- Zeilen 35–42: Testen der Methode [GetCotisations]
- Zeilen 45–53: Testen der Methode [GetEmploye]
- Zeilen 56–65: Testen der Methode [GetEmploye], wenn eine Ausnahme auftritt.
Bei der Projektgenerierung wird die DLL [pam-dao-spring-nhibernate.dll] im Ordner [bin/Release] erstellt:
![]() |
Wir laden die DLL [pam-dao-spring-nhibernate.dll] mit dem Tool [NUnit-Gui], Version 2.5, und führen die Tests aus:

Oben waren die Tests erfolgreich.
2.2.4. Generieren der [dao]-Schicht-DLL mit „ “
Sobald die Klasse [PamDaoNHibernate] geschrieben und getestet wurde, generieren wir die DLL der [dao]-Schicht wie folgt:
![]() |
- [1], die Testprogramme werden aus der Projekt-Assembly
- [2,3], Projektkonfiguration
- [4], Projektgenerierung
- Die DLL wird im Ordner [bin/Release] generiert [5].











