Inlägg December 2008
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-12-08 23:20
webcontrol i ASP.NET MVC
Jag skrev tidigare om att jag tyckte det kan bli grötigt i de views man skapar när man använder ASP.NET MVC och att jag efterlyste något liknande webcontrols. Läste nyss på Phil Haack's blog om en view engine som heter Spark det verkar vara det jag efterlyste, MÅSTE PROVA.
Postad av Håkan Alexander
Kommentarer (0)
Kategorier:
ASP.NET MVC
2008-12-06 22:57
Systeminformation på startsidan
Vi visste inte riktigt vad vi skulle använda startsidan till på den senaste webbapplikationen jag utvecklade. Så jag förslog för kunden att vi skulle göra något bloggliknande där systemintressenterna skulle kunna skriva meddelanden till användarna. Tex om stundande systemunderhåll, uppdateringsinformation eller information som verksamheten vill ha ut till användarna.
Som vanligt tänkte jag på en till tabell i databasen och en WYSIWYG-editor.
Men häromdagen slog det mig att det vore smartare att bara implementera en RSS-lista på startsidan och lägga en URL i web.config. Då kan man ju enkelt ha olika källor för olika miljöer, utvecklingsmiljön, UAT och produktion. Dessutom är den källan oberoende av databasen vilken i både utveckling och UAT rensas mellan varven. Med denna implementation skulle man enkelt kunna få tex incheckningshistoriken från i detta fallet TFS på startsidan i utveckling, UAT miljön skulle kunna innehålla information om vilka scenarios och buggar som är implementerade som genererats som statisk xml-fil i samband med att det installationspaketet byggs av byggservern och produktion skulle kunna visa det jag beskrev tidigare. För produktion skulle man kunna använda befintligt intranät för att skapa nya inlägg.
Känns som en ganska simpel men flexibel och användbar lösning.
Har inte hunnit kolla om TFS-08 har RSS-flöde på källkodshistoriken. Men hittade denna implementation som borde gå att använda. Och att skriva en RSS-lista tar ju inte många minuter.
Uppdaterat länken!
Postad av Håkan Alexander
Kommentarer (1)
Kategorier:
TFS