<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.oosterkamp.nl/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Thomas Huijer : Team System, .NET Framework</title><link>http://blogs.oosterkamp.nl/blogs/thomas/archive/tags/Team+System/.NET+Framework/default.aspx</link><description>Tags: Team System, .NET Framework</description><dc:language>en</dc:language><generator>CommunityServer 2007.1 (Build: 20917.1142)</generator><item><title>Automated testing en databases</title><link>http://blogs.oosterkamp.nl/blogs/thomas/archive/2007/12/14/unit-testing-en-databases.aspx</link><pubDate>Fri, 14 Dec 2007 21:29:44 GMT</pubDate><guid isPermaLink="false">6da500ce-fa22-46ef-b417-4864733669f6:61</guid><dc:creator>Thomas</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.oosterkamp.nl/blogs/thomas/rsscomments.aspx?PostID=61</wfw:commentRss><comments>http://blogs.oosterkamp.nl/blogs/thomas/archive/2007/12/14/unit-testing-en-databases.aspx#comments</comments><description>&lt;p&gt;Eerlijksheidshalve gebied mij te zeggen dat ik dit artikel eerst &amp;quot;Unit testing en databases&amp;quot; wilde noemen. Maar &lt;a href="http://www.dotned.nl/blogs/dennis_blog/default.aspx" target="_blank"&gt;Dennis Vroegop&lt;/a&gt; corrigeerde me gelijk toen ik het met hem hier over had. Zodra je een database bij je testen gebruikt, zijn het automatisch integration tests. Ik moet Dennis helemaal gelijk geven. Er worden tegenwoordig veel te veel dingen unit-tests genoemd...&lt;/p&gt; &lt;p&gt;Automated testing en databases is een verhaal apart. Er zijn verschillende manieren om het te tackelen, maar in feite heb je twee echte keuzes: je gebruikt &lt;a class="" href="http://en.wikipedia.org/wiki/Mock_object"&gt;mock-objects&lt;/a&gt; of je gebruikt een echte database. Ik gebruik zelf het liefste een echte database. Mijn argument daarvoor is dat je je triggers, stored procedures, etc., etc. ook goed wilt kunnen testen. Dat is met mock-objects gewoon niet te doen.&lt;/p&gt; &lt;p&gt;Een echte database gebruiken heeft wel een nadeel. Je moet er voor zorgen dat je testdata constant is. Als je testen runnen, moet het voor elke testrun wel altijd op dezelfde data zijn. En hoe ga je er voor zorgen dat als je bepaalde data nodig hebt voor een test, dat die data ook altijd bij het runnen van je test in je database zit? Als je een lege tabel nodig hebt voor de ene test en een goed gevulde (zelfde) tabel voor een andere test. Hoe ga je daar mee om op een overzichtelijke manier? Hoe weet je welke data in welke test wordt gebruikt?&lt;/p&gt; &lt;p&gt;De meeste unit-test frameworks hebben daar niet echt ondersteuning voor. Dus voor een hobby projectje voor een &lt;a class="" href="http://www.f1.com/"&gt;Formule1&lt;/a&gt; manager spel, ben ik hier eens mee aan de slag gegaan. Nu gebruik ik zelf eigenlijk altijd de &lt;a class="" href="http://msdn2.microsoft.com/en-us/library/ms243147(VS.80).aspx"&gt;geintegreerde unit-testing van Visual Studio 2005/2008&lt;/a&gt;. Ik weet dat er andere, misschien wel &lt;a class="" href="http://www.mbunit.com/"&gt;betere&lt;/a&gt; zijn, maar ik vind de integratie in VS gewoon lekker. Maar hoe breid ik dit framework nou zo uit, dat ik bovenstaande problemen makkelijk kan oplossen?&lt;/p&gt; &lt;p&gt;De eerste stap was een base-class maken voor mijn testen. Hierin kan ik dan functionaliteit toevoegen die ik nodig heb voor het runnen van mijn database testen.&lt;/p&gt; &lt;div style="font-size:10pt;background:white;color:black;font-family:consolas;"&gt;&lt;/div&gt; &lt;div style="font-size:10pt;background:white;color:black;font-family:consolas;"&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; [&lt;span style="color:#2b91af;"&gt;TestClass&lt;/span&gt;]&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;UnitTestBase&lt;/span&gt;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;TestContext&lt;/span&gt; TestContext { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; &lt;span style="color:blue;"&gt;set&lt;/span&gt;; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color:#2b91af;"&gt;TestInitialize&lt;/span&gt;()]&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; TestInitializeInvoker()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TestInitialize();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;protected&lt;/span&gt; &lt;span style="color:blue;"&gt;virtual&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; TestInitialize()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color:#2b91af;"&gt;TestCleanup&lt;/span&gt;()]&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; TestCleanupInvoker()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TestCleanup();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;protected&lt;/span&gt; &lt;span style="color:blue;"&gt;virtual&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; TestCleanup()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;Volgende stap was om te zorgen dat elke test een connectie naar de database heeft en een transactie start. Door &lt;strong&gt;na&lt;/strong&gt; elke test een Rollback te doen, blijft de database constant qua data. Dus ik maakte een class die tegen de testdatabase kon praten: connecties creeren en openen en scriptjes uitvoeren. De scriptjes zou ik dan opnemen als resource in de test-assembly. Ook koos ik er voor om een DbProviderFactory te gebruiken, zodat ik niet vast hing aan 1 bepaald type database.&lt;/p&gt; &lt;div style="font-size:10pt;background:white;color:black;font-family:consolas;"&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;TestDatabase&lt;/span&gt;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;IDbConnection&lt;/span&gt; GetConnection()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#2b91af;"&gt;DbConnection&lt;/span&gt; connection = DbProvider.CreateConnection();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; connection.ConnectionString = ConnectionString;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;return&lt;/span&gt; connection;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;IDbConnection&lt;/span&gt; OpenConnection()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#2b91af;"&gt;IDbConnection&lt;/span&gt; connection = DbProvider.CreateConnection();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; connection.ConnectionString = ConnectionString;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; connection.Open();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;return&lt;/span&gt; connection;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:blue;"&gt;string&lt;/span&gt; GetSql( &lt;span style="color:blue;"&gt;string&lt;/span&gt; resourceName )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;string&lt;/span&gt; fullResourceName = ResourceAssembly.GetName().Name + ( &lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;.IsNullOrEmpty( ScriptsFolder ) ? &lt;span style="color:#a31515;"&gt;&amp;quot;.&amp;quot;&lt;/span&gt; : &lt;span style="color:#a31515;"&gt;&amp;quot;.&amp;quot;&lt;/span&gt; + ScriptsFolder + &lt;span style="color:#a31515;"&gt;&amp;quot;.&amp;quot;&lt;/span&gt; ) + resourceName;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#2b91af;"&gt;Stream&lt;/span&gt; resourceStream = ResourceAssembly.GetManifestResourceStream( fullResourceName );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;if&lt;/span&gt; ( resourceStream == &lt;span style="color:blue;"&gt;null&lt;/span&gt; )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;throw&lt;/span&gt; &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;FileNotFoundException&lt;/span&gt;( &lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;.Format( &lt;span style="color:#a31515;"&gt;&amp;quot;Resource {0} not found.&amp;quot;&lt;/span&gt;, resourceName ) );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#2b91af;"&gt;TextReader&lt;/span&gt; textReader = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;StreamReader&lt;/span&gt;( resourceStream );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;string&lt;/span&gt; sql = textReader.ReadToEnd();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; textReader.Close();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;return&lt;/span&gt; sql;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; ExecuteSql( &lt;span style="color:blue;"&gt;string&lt;/span&gt; sql )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExecuteSql( sql, &lt;span style="color:blue;"&gt;null&lt;/span&gt; );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; ExecuteSql( &lt;span style="color:blue;"&gt;string&lt;/span&gt; sql, &lt;span style="color:#2b91af;"&gt;IDbTransaction&lt;/span&gt; transaction )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;if&lt;/span&gt; ( &lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;.IsNullOrEmpty( sql ) )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;return&lt;/span&gt;;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;string&lt;/span&gt;[] splittedSql = sql.Split( &lt;span style="color:#a31515;"&gt;&amp;#39;;&amp;#39;&lt;/span&gt; );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;if&lt;/span&gt; ( splittedSql.Length &amp;gt; 1 )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;foreach&lt;/span&gt; ( &lt;span style="color:blue;"&gt;string&lt;/span&gt; singleSql &lt;span style="color:blue;"&gt;in&lt;/span&gt; splittedSql )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExecuteSql( singleSql, transaction );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;else&lt;/span&gt;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#2b91af;"&gt;IDbCommand&lt;/span&gt; command = DbProvider.CreateCommand();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; command.Connection = transaction == &lt;span style="color:blue;"&gt;null&lt;/span&gt; ? GetConnection() : transaction.Connection;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; command.CommandText = sql;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;bool&lt;/span&gt; closeConnection = &lt;span style="color:blue;"&gt;false&lt;/span&gt;;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;if&lt;/span&gt; ( command.Connection.State == &lt;span style="color:#2b91af;"&gt;ConnectionState&lt;/span&gt;.Closed )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; command.Connection.Open();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; closeConnection = &lt;span style="color:blue;"&gt;true&lt;/span&gt;;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;if&lt;/span&gt; (transaction != &lt;span style="color:blue;"&gt;null&lt;/span&gt; )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; command.Transaction = transaction;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; command.ExecuteNonQuery();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;if&lt;/span&gt; ( closeConnection )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; command.Connection.Close();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; ExecuteScript( &lt;span style="color:blue;"&gt;string&lt;/span&gt; scriptName, &lt;span style="color:#2b91af;"&gt;IDbTransaction&lt;/span&gt; transaction )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExecuteSql( GetSql( scriptName ), transaction );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; ExecuteScript( &lt;span style="color:blue;"&gt;string&lt;/span&gt; scriptName )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExecuteScript( scriptName, &lt;span style="color:blue;"&gt;null&lt;/span&gt; );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; ExecuteDefaultScript()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExecuteScript( defaultScriptName );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; ExecuteDefaultScript( &lt;span style="color:#2b91af;"&gt;IDbTransaction&lt;/span&gt; transaction)&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExecuteScript( defaultScriptName, transaction );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;}&lt;/p&gt;&lt;/div&gt; &lt;p&gt;Maar wat ik niet wilde, was om mijn base-class te laten bepalen tegen welke database de testen zouden worden gerund. Dus ik had nog een class nodig om dit te bepalen. Ik wilde niet alles in een config file stoppen, maar een aparte class laten bepalen in welke type database we testen. Door middel van &lt;a class="" href="http://en.wikipedia.org/wiki/Inversion_of_control"&gt;Inversion of Control&lt;/a&gt; laat ik dat dan een andere class bepalen.&lt;/p&gt; &lt;p&gt;Om nu een test te laten runnen en automatisch een Rollback te doen na het uitvoeren van een test, maakte ik een Attribute.&lt;/p&gt; &lt;div style="font-size:10pt;background:white;color:black;font-family:consolas;"&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; [&lt;span style="color:#2b91af;"&gt;AttributeUsage&lt;/span&gt;( &lt;span style="color:#2b91af;"&gt;AttributeTargets&lt;/span&gt;.Method )]&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;AutoRollbackAttribute&lt;/span&gt; : &lt;span style="color:#2b91af;"&gt;Attribute&lt;/span&gt;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt; &lt;p&gt;Als ik dat attribute boven een test zet, dan zorgt de UnitTestBase er voor dat de Rollback automatisch wordt uitgevoerd.&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;protected&lt;/span&gt; &lt;span style="color:blue;"&gt;virtual&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; TestInitialize()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _connection = &lt;span style="color:#2b91af;"&gt;TestDatabase&lt;/span&gt;.OpenConnection();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; StartTransaction();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;protected&lt;/span&gt; &lt;span style="color:blue;"&gt;virtual&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; TestCleanup()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;if&lt;/span&gt; ( HasAutoRollbackAttribute() )&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Transaction.Rollback();&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;div style="font-size:10pt;background:white;color:black;font-family:consolas;"&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:blue;"&gt;bool&lt;/span&gt; HasAutoRollbackAttribute()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#2b91af;"&gt;MethodInfo&lt;/span&gt; testMethod = &lt;span style="color:blue;"&gt;this&lt;/span&gt;.GetType().GetMetho( TestContext.TestName );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;object&lt;/span&gt;[] attributes = testMethod.GetCustomAttributes( &lt;br /&gt;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; typeof&lt;/span&gt;( &lt;span style="color:#2b91af;"&gt;AutoRollbackAttribute&lt;/span&gt; ), &lt;span style="color:blue;"&gt;false&lt;/span&gt; );&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;return&lt;/span&gt; attributes.Length &amp;gt; 0;&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp; } &lt;/p&gt;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt;Een test zou dat alleen (behalve het TestMethod attribute natuurlijk) dan alleen het AutoRollback attribute moeten hebben, om er voor te zorgen dat de test niets veranderd in de database.&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;div style="font-size:10pt;background:white;color:black;font-family:consolas;"&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color:#2b91af;"&gt;TestMethod&lt;/span&gt;]&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color:#2b91af;"&gt;AutoRollback&lt;/span&gt;]&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; SomeTest()&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //test implementation&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin:0px;"&gt; Hiermee ben ik dus al een heel end. Maar ik wil ook toch testdata kunnen initialiseren voor een bepaalde test. Data die je alleen voor die test nodig hebt. Maar daar blog ik een volgende keer over. Dan zal ik ook de sourcecode beschikbaar stellen van dit mini &amp;#39;testframework&amp;#39;.&lt;/p&gt; &lt;p style="margin:0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://blogs.oosterkamp.nl/aggbug.aspx?PostID=61" width="1" height="1"&gt;</description><category domain="http://blogs.oosterkamp.nl/blogs/thomas/archive/tags/Team+System/default.aspx">Team System</category><category domain="http://blogs.oosterkamp.nl/blogs/thomas/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://blogs.oosterkamp.nl/blogs/thomas/archive/tags/.NET+Framework/default.aspx">.NET Framework</category><category domain="http://blogs.oosterkamp.nl/blogs/thomas/archive/tags/unit-testing/default.aspx">unit-testing</category></item><item><title>Visual Studio 2008 RTM is beschikbaar...</title><link>http://blogs.oosterkamp.nl/blogs/thomas/archive/2007/11/19/visual-studio-team-system-2008-team-suite-rtm-is-beschikbaar.aspx</link><pubDate>Mon, 19 Nov 2007 11:40:31 GMT</pubDate><guid isPermaLink="false">6da500ce-fa22-46ef-b417-4864733669f6:76</guid><dc:creator>Thomas</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.oosterkamp.nl/blogs/thomas/rsscomments.aspx?PostID=76</wfw:commentRss><comments>http://blogs.oosterkamp.nl/blogs/thomas/archive/2007/11/19/visual-studio-team-system-2008-team-suite-rtm-is-beschikbaar.aspx#comments</comments><description>&lt;p&gt;Op de MSDN Subscriber site is de Visual Studio Team System 2008 Team Suite RTM beschikbaar! Ze hadden al beloofd dat ie &amp;#39;early next week&amp;#39; beschikbaar zou zijn, en maandag, einde van de ochtend, net na de eerste koppen koffie...Ja, dat kwalificieert wel als &amp;#39;early next week&amp;#39;.&lt;/p&gt;&lt;img src="http://blogs.oosterkamp.nl/aggbug.aspx?PostID=76" width="1" height="1"&gt;</description><category domain="http://blogs.oosterkamp.nl/blogs/thomas/archive/tags/Team+System/default.aspx">Team System</category><category domain="http://blogs.oosterkamp.nl/blogs/thomas/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://blogs.oosterkamp.nl/blogs/thomas/archive/tags/.NET+Framework/default.aspx">.NET Framework</category><category domain="http://blogs.oosterkamp.nl/blogs/thomas/archive/tags/Visual+Studio+2008/default.aspx">Visual Studio 2008</category></item></channel></rss>