K
Konstantin Denerz
Hallo,
hier ist ein kleines Beispiel zum Einsatz von Spring.Net mit Ado.Net beim Unit-Tests mit NUnit.
Hierbei werden 2 Methoden eins DAO's (Data Access Object) getestet.
hier ist das DAO Interface:
das Interface IBubuDao hat 2 Methoden:
das Geschäftsobjekt Bubu:
Die Implementierung des Interfaces IBubuDao:
In dieser Implementierung erbt BubuDao von der Spring-Klasse AdoDaoSupport. Diese stellt Klassen und Methoden für vereinfachte Datenbankzugriffe bereit. Eine dieser Klassen ist die Klasse AdoTemplate. In dem Beispiel werden 2 Methoden der Klasse AdoTemplate verwendet:
Die Implementierung des Interfaces IResultSetExtractor
Das App.config File (Anwendungskonfiguration):
Die Springkonfiguration:
Und zuletzt der Unit-Test:
Die Klasse BubuTest erbt von der Spring-Klasse AbstractDependencyInjectionSpringContextTests aus dem Assembly Spring.Testing.NUnit, die die 2 Methoden SetUp und TearDown schon implementiert. Nach dem die Eigenschaft ConfigLocations überschrieben wird und man im Getter die Pfade zu den Springkonfigurationsdateien einträgt, wird beim Ausführen des Tests in der SetUp-Methode ein ApplicationContext erstellt.
Weiterhin werden die Abhängigkeiten durch Dependency Injection (DI) automatisch aufgelöst (Autowiring). (falls es nicht deaktiviert wird) So bekommen die 2 Attribute, bubuDao und template, Objekte gleichen Typs zugewiesen, die in der Springkonfiguration definiert sind. Beim DI bekommt template über den Typ das entsprechende Objekt zugewiesen, da der Name ungleich dem ist, der in der Springkonfiguration definiert ist.
In der Springkonfiguration ist der DBProvider System.Data.Odbc definiert. Wer diesen benutzen will muss folgende Springkonfiguration in die Datei dbproviders.xml in dem Projekt Spring.Data im Verzeichnis Data/Common einfügen:
Hier findet man die vorhanden DBProvider aufgelistet: DB-Provider
Gruß Konstantin
hier ist ein kleines Beispiel zum Einsatz von Spring.Net mit Ado.Net beim Unit-Tests mit NUnit.
Hierbei werden 2 Methoden eins DAO's (Data Access Object) getestet.
hier ist das DAO Interface:
C#:
using System;
using System.Collections.Generic;
using Training.NUnit.SpringWithAdo.Domain;
namespace Training.NUnit.SpringWithAdo.Dao
{
public interface IBubuDao
{
IList<Bubu> GetBubuByName(string name);
void SaveBubu(Bubu bubu);
}
}
das Interface IBubuDao hat 2 Methoden:
- GetBubuByName, die eine Liste von Bubus laden sollte, falls der Name der Bubus gleich dem Wert des Parameters name ist
- und SaveBubu, die das Geschäftsobjekt Bubu in der Datenbank dauerhaft (persistent) speichern sollte.
das Geschäftsobjekt Bubu:
C#:
using System;
namespace Training.NUnit.SpringWithAdo.Domain
{
public class Bubu
{
private long id;
private string name;
public long Id {
get { return id; }
set { id = value; }
}
public string Name {
get { return name; }
set { name = value; }
}
public Bubu(){
}
public Bubu(long id, string name)
{
this.id = id;
this.name = name;
}
}
}
Die Implementierung des Interfaces IBubuDao:
C#:
using System;
using System.Collections.Generic;
using Training.NUnit.SpringWithAdo.Domain;
using System.Data;
using Spring.Data;
namespace Training.NUnit.SpringWithAdo.Dao.Internal
{
public class BubuDao:AdoDaoSupport,IBubuDao
{
/// <summary>
/// Lädt alle Bubus mit einem bestimmten Namen
/// </summary>
/// <param name="name">Name der Bubus, die geladen werden sollen</param>
/// <returns>Liste mit Bubus</returns>
public IList<Bubu> GetBubuByName(string name)
{
return (IList<Bubu>) this.AdoTemplate.QueryWithResultSetExtractor(
CommandType.Text,"SELECT * FROM Bubu WHERE name='"+name+"'",
new BubuResultSetExtractor());
}
/// <summary>
/// Speichert Bubu in der DB
/// </summary>
/// <param name="bubu">Bubu-Objekt</param>
public void SaveBubu(Bubu bubu)
{
this.AdoTemplate.ExecuteNonQuery(CommandType.Text,
"INSERT INTO bubu values ("+string.Join(", ",
new string[]{"'"+bubu.Id.ToString()+"'","'"+bubu.Name+"'"})
+")");
}
}
}
- ExecuteNonQuery kapselt die gleichnamige Methode der Schnittstelle IDbCommand im Assembly System.Data
- QueryWithResultSetExtractor kapselt die Methode ExecuteReader der Schnittstelle IDbCommand im Assembly System.Data und verwendet für das Ergebnis eine Implementierung von IResultSetExtractor, der über Ergebnis (vom Typ IDataReader) iteriert und ein Ergebnisobjekt erstellt.
Die Implementierung des Interfaces IResultSetExtractor
C#:
using System;
using System.Collections.Generic;
using Spring.Data;
using Training.NUnit.SpringWithAdo.Domain;
namespace Training.NUnit.SpringWithAdo.Dao.Internal
{
public class BubuResultSetExtractor:IResultSetExtractor
{
public object ExtractData(System.Data.IDataReader reader)
{
IList<Bubu> result=new List<Bubu>();
while(reader.Read()){
Bubu bubu=new Bubu();
bubu.Id=long.Parse(reader["id"].ToString());
bubu.Name=reader["name"].ToString();
result.Add(bubu);
}
return result;
}
}
}
Das App.config File (Anwendungskonfiguration):
XML:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
<section name="parsers" type="Spring.Context.Support.ConfigParsersSectionHandler, Spring.Core" />
</sectionGroup>
<section name="DatabaseConfiguration" type="System.Configuration.NameValueSectionHandler" />
</configSections>
<spring>
<parsers>
<parser type="Spring.Remoting.RemotingConfigParser, Spring.Services" />
<parser namespace="http://www.springframework.net/database" type="Spring.Data.DatabaseConfigParser, Spring.Data" schemaLocation="assembly://Spring.Data/Spring.Data/spring-database.xsd" />
</parsers>
<context caseSensitive="false" name="spring.root">
<resource uri="~/Config/Spring/dao.xml" />
</context>
</spring>
<DatabaseConfiguration>
<add key="db.connectionstring" value="DRIVER={MaxDB};Datasource Name=meinDatasourcename;Server=localhost;UID=meinName;Pwd=meinPasswort;Database=meineDatenbank" />
</DatabaseConfiguration>
</configuration>
Die Springkonfiguration:
XML:
<?xml version="1.0" encoding="utf-8"?>
<objects xmlns="http://www.springframework.net" xmlns:d="http://www.springframework.net/database">
<d:dbProvider id="DbProvider" provider="System.Data.Odbc" connectionString="${db.connectionstring}" />
<object id="adoTemplate" type="Spring.Data.AdoTemplate, Spring.Data">
<property name="DbProvider" ref="DbProvider" />
</object>
<object name="appConfigPropertyHolder" type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
<property name="configSections">
<value>DatabaseConfiguration</value>
</property>
</object>
<object name="BubuDao" type="Training.NUnit.SpringWithAdo.Dao.Internal.BubuDao, Training.NUnit.SpringWithAdo">
<property name="adoTemplate" ref="adoTemplate">
</property>
</object>
</objects>
Und zuletzt der Unit-Test:
C#:
#if TEST
using NUnit.Framework;
using System;
using System.Data;
using System.Collections.Generic;
using Training.NUnit.SpringWithAdo.Domain;
using Training.NUnit.SpringWithAdo.Dao;
using Spring.Data;
using Spring.Testing.NUnit;
namespace Training.NUnit.SpringWithAdo
{
[TestFixture]
public class BubuTest:AbstractDependencyInjectionSpringContextTests
{
private IBubuDao bubuDao;
public IBubuDao BubuDao {
get { return bubuDao; }
set { bubuDao = value; }
}
private AdoTemplate template;
public AdoTemplate Template {
get { return template; }
set { template = value; }
}
protected override string[] ConfigLocations {
get { return new string[]{
@"Config\Spring\dao.xml"
}; }
}
[Test]
public void GetBubus()
{
//speichert Bubu für den Test
this.Template.ExecuteNonQuery(CommandType.Text,"insert into bubu values (5,'FooBar')");
//prüft, ob ein Bubu mit dem Namen FooBar angelegt wurde
IList<Bubu> list = this.BubuDao.GetBubuByName("FooBar");
Assert.IsTrue(list.Count>0,"Liste der Bubus ist 0. Es wurden keine Bubus geladen/angelegt.");
}
[Test]
public void SaveBubu(){
this.BubuDao.SaveBubu(new Bubu(1,"BarFoo"));
//prüft, ob ein Bubu mit der ID = 1 angelegt wurde
DataTable dataTable = this.Template.DataTableCreate(CommandType.Text,"select * from bubu where id = 1");
Assert.IsTrue(dataTable.Rows.Count!=0,"Anzahl der Bubus ist 0. Es wurden keine Bubus gespeichert.");
}
protected override void OnTearDown()
{
base.OnTearDown();
//räumt auf
this.Template.ExecuteNonQuery(CommandType.Text,"delete from bubu where id = 1 or id = 5");
}
}
}
#endif
Die Klasse BubuTest erbt von der Spring-Klasse AbstractDependencyInjectionSpringContextTests aus dem Assembly Spring.Testing.NUnit, die die 2 Methoden SetUp und TearDown schon implementiert. Nach dem die Eigenschaft ConfigLocations überschrieben wird und man im Getter die Pfade zu den Springkonfigurationsdateien einträgt, wird beim Ausführen des Tests in der SetUp-Methode ein ApplicationContext erstellt.
Weiterhin werden die Abhängigkeiten durch Dependency Injection (DI) automatisch aufgelöst (Autowiring). (falls es nicht deaktiviert wird) So bekommen die 2 Attribute, bubuDao und template, Objekte gleichen Typs zugewiesen, die in der Springkonfiguration definiert sind. Beim DI bekommt template über den Typ das entsprechende Objekt zugewiesen, da der Name ungleich dem ist, der in der Springkonfiguration definiert ist.
In der Springkonfiguration ist der DBProvider System.Data.Odbc definiert. Wer diesen benutzen will muss folgende Springkonfiguration in die Datei dbproviders.xml in dem Projekt Spring.Data im Verzeichnis Data/Common einfügen:
XML:
<object id="Odbc-2.0" type="Spring.Data.Common.DbProvider, Spring.Data" singleton="false">
<constructor-arg name="dbMetaData">
<object type="Spring.Data.Common.DbMetadata">
<constructor-arg name="productName" value="Odbc"/>
<constructor-arg name="assemblyName" value="System.Data" />
<constructor-arg name="connectionType" value="System.Data.Odbc.OdbcConnection, System.Data"/>
<constructor-arg name="commandType" value="System.Data.Odbc.OdbcCommand, System.Data" />
<constructor-arg name="parameterType" value="System.Data.Odbc.OdbcParameter, System.Data" />
<constructor-arg name="dataAdapterType" value="System.Data.Odbc.OdbcDataAdapter, System.Data" />
<constructor-arg name="commandBuilderType" value="System.Data.Odbc.OdbcCommandBuilder, System.Data" />
<constructor-arg name="commandBuilderDeriveParametersMethod" value="DeriveParameters"/>
<constructor-arg name="parameterDbType" value="System.Data.Odbc.OdbcType, System.Data" />
<constructor-arg name="parameterDbTypeProperty" value="OdbcType"/>
<constructor-arg name="parameterIsNullableProperty" value="IsNullable"/>
<constructor-arg name="parameterNamePrefix" value="?"/>
<constructor-arg name="exceptionType" value="System.Data.Odbc.OdbcException, System.Data"/>
<constructor-arg name="useParameterNamePrefixInParameterCollection" value="false"/>
<constructor-arg name="bindByName" value="false"/>
<constructor-arg name="errorCodeExceptionExpression" value="Errors[0].NativeError.ToString()"/>
<property name="ErrorCodes.BadSqlGrammarCodes">
<value>156,170,207,208</value>
</property>
<property name="ErrorCodes.PermissionDeniedCodes">
<value>229</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>2627,8114,8115</value>
</property>
<property name="ErrorCodes.DeadlockLoserCodes">
<value>1205</value>
</property>
</object>
</constructor-arg>
</object>
<alias name="Odbc-2.0" alias="System.Data.Odbc"/>
Hier findet man die vorhanden DBProvider aufgelistet: DB-Provider
Gruß Konstantin
Zuletzt bearbeitet von einem Moderator: