/Images/MainImage/Håkan Alexander.jpg finns inte.

NHibernate

2009-04-23 18:41

Filmtips

Om du bara skall se en film i helgen se denna! Nej då jag skojar.

Men nu har äntligen inspelningarna från ALT.NET spåret på Öredev 2008 blivit klara.

Dom finns här http://www.viddler.com/explore/oredev/

Jag kan speciellt rekomendera Ayendes session om Active Record. Den var mycket bra, tänkvärd och underhållande.

Se den!

/Håkan 


Postad av Håkan Alexander

Kommentarer (0)   Kategorier:  Oredev2008    NHibernate    Tools



2008-12-10 10:10

Integrationstest mot databas

Jag fick en kommentar från Karl på min blogg om Dataaccess och kundnytta där han undrade om hur jag gjorde integrationstester mot databasen så jag skriver om det.

Det viktigaste är att man har känt data i databasen när man skall göra dessa integrationstester.

För att inte störa eller störas av andra som jobbar mot databasen behöver man en egen databas jag vill helst köra lokalt för att slippa att testerna tar onödigt lång tid.

Jag har använt mig av NDbUnit  för att säkerställa att jag har känt data i databasen innan testerna körs. Det är ett litet program som kan fixa till data på massor av sätt, jag har valt att låta den tömma databasen och fylla på med mitt testdata före integrationstesterna körs.

I mitt senaste projekt hade vi en DBA med som jobbade mot en gemensam databas, för att säkerställa att vi var i synk gjorde jag så att testkoden kan gå mot olika databaser beroende på behov.

Nedan finns källkoden som körs före något test i det namespace koden ligger. Alltså den kod som puttar in det data i databasen jag vill testa mot.

Sen kan jag enkelt skriva tester som verifierar tex att mina mappningar är korrekt om jag kör NHibernate eller att min dataaccess kod sätter alla properties.

    1 using System;

    2 

    3 using NUnit.Framework;

    4 

    5 using DBAccess;

    6 

    7 namespace DBAccessTest

    8 {

    9     [TestFixture]

   10     public class OrderTests

   11     {

   12         [Test]

   13         public void CanGetOrderById()

   14         {

   15             var dao = new OrderDao();

   16 

   17             var order = dao.GetById(1);

   18 

   19             Assert.That(order, Is.Not.Null);

   20             Assert.That(order, Has.Property("Created").EqualTo(DateTime.Parse("2008-12-10 13:34")));

   21         }

   22 

   23         [Test]

   24         public void OrderHasOrderRows()

   25         {

   26             var dao = new OrderDao();

   27 

   28             var order = dao.GetById(2);

   29 

   30             Assert.That(order.OrderRows, Has.Count.EqualTo(3));

   31         }

   32     }

   33 }

OBS. Testar NUnit 2.5 därav syntax som inte finns i 2.4!

Det är lika lätt att skriva tester för insert, update och delete. Dessa kan man köra i en transaktion runt själva testet och rulla tillbaka för att det inte skall påverka följande tester.

 

    1 using System.Data;

    2 

    3 using NUnit.Framework;

    4 

    5 using NDbUnit.Core;

    6 using NDbUnit.Core.SqlClient;

    7 

    8 namespace DBAccessTest

    9 {

   10     // Supported enviroments

   11     public enum TestDatabases

   12     {

   13         local,

   14         remote

   15     }

   16 

   17     // Setup for tests in the same namespace

   18     [SetUpFixture]

   19     public class SetupDatabaseWithKnownData

   20     {

   21         // Change this when you would like to verify other database

   22         private TestDatabases currentDatabase = TestDatabases.local;

   23 

   24         // Filename of data stored during test

   25         private string original_data_file = "org_data.xml";

   26 

   27         // Connections to different databases

   28         private string local_connection = @"Data Source=.\SQLEXPRESS;Initial Catalog=testdatabase;Integrated Security=True";

   29         private string remote_connection = @"Data Source=192.168.1.120;Initial Catalog=testdatabase;Integrated Security=True";

   30 

   31         // Return current connection

   32         private string CurrentConnectionString()

   33         {

   34             string connectionString = "";

   35 

   36             switch (currentDatabase)

   37             {

   38                 case TestDatabases.local:

   39                     connectionString = local_connection;

   40                     break;

   41 

   42                 case TestDatabases.remote :

   43                     connectionString = remote_connection;

   44                     break;

   45             }

   46 

   47             return connectionString;

   48         }

   49 

   50         // Runs once prior to any test in this namespace

   51         [SetUp]

   52         public void SetupDatabase()

   53         {

   54             // Creating a new databaseSetup object with the relevant connectionstring

   55             INDbUnitTest databaseSetup = new SqlDbUnitTest(CurrentConnectionString());

   56 

   57             // Load the database schema, tables not in this schema will be ignored.

   58             databaseSetup.ReadXmlSchema("database_schema.xsd");

   59 

   60             // Save current data if running test against other source than my private

   61             if (currentDatabase != TestDatabases.local)

   62             {

   63                 DataSet original = databaseSetup.GetDataSetFromDb();

   64                 original.WriteXml(original_data_file);

   65             }

   66 

   67             // Load my known data into the databaseSetup

   68             databaseSetup.ReadXml("current_test_data.xml");

   69 

   70             // Insert that data into the database, clear all other data.

   71             databaseSetup.PerformDbOperation(DbOperationFlag.CleanInsertIdentity);

   72         }

   73 

   74         // Runs after all tests been executed

   75         [TearDown]

   76         public void RestoreDatabase()

   77         {

   78             // If not my database resore to original data.

   79             if (currentDatabase != TestDatabases.local)

   80             {

   81                 INDbUnitTest databaseSetup = new SqlDbUnitTest(CurrentConnectionString());

   82 

   83                 databaseSetup.ReadXmlSchema("database_schema.xsd");

   84 

   85                 // Load the data we stored earlier

   86                 databaseSetup.ReadXml(original_data_file);

   87 

   88                 // Clear and resore data from prior to tests

   89                 databaseSetup.PerformDbOperation(DbOperationFlag.CleanInsertIdentity);

   90             }

   91         }

   92     }

   93 }

Det finns en bugg i NDbUnit 1.2 som gör att CleanInsertIdentity inte fungerar om man har ForeignKey relations i sin databas. Det finns bloggar om hur man löser det.

 


Postad av Håkan Alexander

Kommentarer (2)   Kategorier:  TDD    NHibernate



2008-11-29 00:10

Dataaccess och kundnytta

Jag startade ett projekt med att använda NHibernate för dataaccess direkt mot tabeller som mappade 1 till 1 mot mina domänobjekt. Det var tidigt i projektet och jag ville fort få fram någon form av riktig upplevelse för kunden, kunden höll i samma veva på att forma den organisation och rutiner som systemet skulle stödja så det var upplagt för många förändringar av datamodellen. En bit in i projektet togs det fram en ny datamodell för databasen av en databasexpert, den var naturligt nog ganska olik den jag startat med. Den modellen tog hänsyn till många aspekter som min saknade.

Jag blev i samma veva införstådd med att driftorganisationen inte accepterade att applikationer fick direktaccess till tabellerna  utan endast via storedprocedures. Hmm, hur går det ihop med NHibernate? När jag fick klartecken från driften att min applikation skulle få hämta data vi vyer men sköta uppdateringarna via procedurer visade det sig att NHibernate hade ett ganska bra stöd för detta. Att hämta data via vyer gjorde det bättre eftersom jag nu enkelt kunde sätta ihop den nya databasmodellen med hjälp av vyer så att den stämde med min datamodell i applikationen. Uppdateringen var dock en annan visa, även om NHibernate stöder att varje klass har en insert, update och delete -procedur så blev det lite bök med det. Det funkar bra om man inte använder identity i databasen utan låtar NHibernate hantera idgenereringen. Så där fick jag göra en fix. Jag såg dock att stöd för Identity kommer med nästa version, förslaget ligger klart i 2.1 Alpha 1.

Allt detta bara för att komma fram till vad jag egentligen ville säga.

Det jag märkt är att dataaccess tar ganska mycket mer tid i anspråk nu när vyer och procedurer måste skapas och underhållas så fort databasmodellen ändras. Jag har inte sett detta så tydligt förut eftersom man sällan har möjlighet att få en så här jämförelse. Om vi bara hade haft mätvärden på farten i projektet. Då hade man kunnat se hur stor skillnaden är, i siffror.

Jag är dock glad att jag skrivit integrationstester för att testa all dataaccess mot känt testdata, annars vet jag inte hur lång tid det tagit att fixa till vyer och procedurer efter databasförändringarna.


Postad av Håkan Alexander

Kommentarer (2)   Kategorier:  NHibernate