MSDN Magazine Launch Issue - February 15, 2008 - (Page 71) begin transaction -- Execute test -- We can clean up when the test passes successfully; otherwise, it -- is up to the engine to clean up the transaction when the -- connection is closed rollback transaction In an ADO.NET transaction, execute the code shown in Figure 6. To use System.Transactions, take a look at Figure 7. Figure 6 ADO.NET Transaction [TestMethod()] public void ADONetTransactionSample() { base.ExecutionContext.Transaction = base.ExecutionContext.Connection.BeginTransaction(); try { DatabaseTestActions testActions = this.ADONetTransactionSampleData; // Execute the test script Trace.WriteLineIf( (testActions.TestAction != null), “Executing test script ”); ExecutionResult[] testResults = TestService.Execute( this.ExecutionContext, this.ExecutionContext, testActions.TestAction); Of these three options, T-SQL and ADO.NET transactions work if you’re not using the pre/post test scripts to set up the database or verify the results of the test; remember, the pre/post scripts are executed using a different connection so their modifications will not be rolled back. Using System.Transactions, the Privileged and Execution connections have already been created so they must be enlisted in the ambient transaction created when the TransactionScope is instantiated, but any changes will be rolled back. System.Transactions Because using ambient transactions (as in the System.Transactions example shown previously) is the best comprehensive solution, let’s drill into the solution more. (You may also visit msdn2.microsoft.com/ms172152 for more background.) The ambient transaction is used across two different connections that may have different lifetimes, so the Distributed Transaction Coordinator (DTC) service must be used to manage the transaction’s lifetime. This means that in order to use System.Transactions, the database’s DTC service must be started for the test to pass. If the service is not started, your test will fail with an exception like the following: Test method TestSamples.DatabaseUnitTest1.SystemTransactionsExample threw exception: System.Data.SqlClient.SqlException: MSDTC on server ‘(LOCAL)\SQLEXPRESS’ is unavailable. } } finally { base.ExecutionContext.Transaction.Rollback(); } Figure 7 Using System.Transactions [TestMethod()] public void SystemTransactionsExample() { using (TransactionScope transactionScope = new System.Transactions.TransactionScope( TransactionScopeOption.Required)) { base.ExecutionContext.Connection.EnlistTransaction( Transaction.Current); base.PrivilegedContext.Connection.EnlistTransaction( Transaction.Current); DatabaseTestActions testActions = this.SystemTransactionsExampleData; // Execute the pre-test script Trace.WriteLineIf((testActions.PretestAction != null), “Executing pre-test script ”); ExecutionResult[] pretestResults = TestService.Execute( this.PrivilegedContext, this.PrivilegedContext, testActions.PretestAction); // Execute the test script Trace.WriteLineIf((testActions.TestAction != null), “Executing test script ”); ExecutionResult[] testResults = TestService.Execute( this.ExecutionContext, this.PrivilegedContext, testActions.TestAction); // Execute the post-test script Trace.WriteLineIf((testActions.PosttestAction != null), “Executing post-test script ”); ExecutionResult[] posttestResults = TestService.Execute( this.PrivilegedContext, this.PrivilegedContext, testActions.PosttestAction); Modifying each method to use an ambient transaction is tedious at best; most likely, you will want to group all the transactional tests together in one class and then modify the class so that a transaction is started and stopped for each test (see Figure 8). The test harness that shipped with Visual Studio 2005 allows you to run a unit test multiple times, each time with a different set of input parameters. Documentation describing how to use this harness can be found in “Coding a Data-Driven Unit Test” at msdn2.microsoft.com/ms182527 and in “Walkthrough: Using a Configuration File to Define a Data Source” at msdn2.microsoft.com/ms243192. Figure 8 Using Transactions for Each Test TransactionScope _ambientTransaction; [TestInitialize()] public void TestInitialize() { // Create the transaction prior to the // connections being created. When the // connections are created they will // automatically enlist in the transaction ambientTransaction = new TransactionScope( TransactionScopeOption.Required); } base.InitializeTest(); Data-Driven Testing [TestCleanup()] public void TestCleanup() { // Since Complete() was not called, disposing // of the ambient transaction will cause all // changes to be rolled back ambientTransaction.Dispose(); } base.CleanupTest(); } } Database Unit Testing launch2008 71 http://msdn2.microsoft.com/ms172152 http://msdn2.microsoft.com/ms182527 http://msdn2.microsoft.com/ms182527 http://msdn2.microsoft.com/ms243192
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.