Proper way to maintain database known state by rolling back transactions in NUnit, Sql Server and UI Testing Proper way to maintain database known state by rolling back transactions in NUnit, Sql Server and UI Testing selenium selenium

Proper way to maintain database known state by rolling back transactions in NUnit, Sql Server and UI Testing


Database snapshots!

Save this script and name it "create_db_snapshot.sql"

/* Create a database snapshot */USE master;CREATE DATABASE Your_Database_Snapshot ON(     NAME = Your_Database,     FILENAME = 'C:\Snapshots\Your_Database_Snapshot.ss' )AS SNAPSHOT OF Your_Database;GO

Also, save this script and name it "restore_db_from_snapshot.sql"

USE master;RESTORE DATABASE Your_Database from DATABASE_SNAPSHOT = 'Your_Database_Snapshot';GO

Example:

using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;using Microsoft.SqlServer.Management.Smo;using Microsoft.SqlServer.Management.Common;using System.IO;using System.Data.SqlClient;[SetUp]public void TestSetUp(){    string sqlConnectionString = @"server=test.database.com;uid=your_db_username;pwd=your_db_password;database=Your_Database;";    string script = File.ReadAllText(@"~/create_db_snapshot.sql");    SqlConnection conn = new SqlConnection(sqlConnectionString);    Server server = new Server(new ServerConnection(conn));    server.ConnectionContext.ExecuteNonQuery(script);}[TearDown]public void TearDown(){    string sqlConnectionString = @"server=test.database.com;uid=your_db_username;pwd=your_db_password;database=Your_Database;";    string script = File.ReadAllText(@"~/restore_db_from_snapshot.sql");    SqlConnection conn = new SqlConnection(sqlConnectionString);    Server server = new Server(new ServerConnection(conn));    server.ConnectionContext.ExecuteNonQuery(script);}

Snapshot documentation: https://msdn.microsoft.com/en-us/library/ms175158.aspx

Code credit for executing .sql file: https://stackoverflow.com/a/1728859/3038677

You might also need to run this script prior to executing restore_db_from_snapshot.sql...

/* Kill all current connections to Your_Database */use master;DECLARE @kill varchar(8000) = '';SELECT @kill = @kill + 'kill ' + CONVERT(varchar(5), spid) + ';'FROM master..sysprocesses WHERE dbid = db_id('Your_Database')


I use database snapshots for Selenium testing of my web application. In the Setup method I roll back the database to a snapshot taken just after restoring the database from production. This guarantees the database is in the same state for each test run, but still allows you to test the UI. I have created several temporary stored procedures, for example #usp_restore_snapshot, to avoid littering the database and the unit test with SQL code just used for testing..


One way is to use https://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx and it will rollback everything back automatically, even on test failure, because there is no commit statement.

like:

[Test]public void SomeTest() {    using (TransactionScope scope = new TransactionScope())    {        // here comes your test    }}

A "better" and "safer" way is the way you told in your question doing it via TearDown:

[TestFixture]public class YourFixture{    private TransactionScope scope;    [SetUp]    public void TestSetUp()    {        scope = new TransactionScope();    }    [TearDown]    public void TearDown()    {        scope.Dispose();    }    [Test]    public void SomeTest()    {        // here comes your test     }}

Why? Because NUnit is your garanty that TearDown will be called.