3

I'm looking for a project/tool that will insert data into a database before a test and roll it back after a test has run.

I know that ruby on rails has yaml fixtures, so I was hoping there is a project out there for .net projects.

Scott Willeke
  • 8,884
  • 1
  • 40
  • 52
Eric Neunaber
  • 431
  • 3
  • 10
  • Fixtures are a Rails-added feature. Also different from the term 'test fixture' which means a grouping of xUnit tests that share common setup or teardown code. – Gishu Feb 24 '09 at 15:04
  • That is correct. I found it hard to search for this because of how the word "fixture" is used in .net – Eric Neunaber Feb 24 '09 at 15:32

2 Answers2

2

There are a couple good ways to provide data to tests in .NET. One is to use features built into NUnit such as parameterized tests and theories.

Parameterized Tests:

The TestCaseAttribute allows you to easily supply hard-coded data to a test as in the following example from nunit.org:

[TestCase(12,3, Result=4)]
[TestCase(12,2, Result=6)]
[TestCase(12,4, Result=3)]
public int DivideTest(int n, int d)
{
  return( n / d );
}

The TestCaseDataAttribute lets you get much more fancy in supplying data (such as returning data from a database).

Transactions for Rollback

Another trick often used is relying on transactions. Basically, start a Transaction before the test, and roll it back after. This can even be automated using a base class so you're tests don't deal with the transactions themselves at all. For example, you might have a base class for your test fixture like the following:

public class TestBase
{
    private TransactionScope _transacation;

    [SetUp]
    public virtual void InitializeTest()
    {
        //NOTE: Base class TestInitialize methods are called before test Initialize methods in derived class.

        // Setup a DB transcation to roll everything back after the tests.
        if (_transacation != null)
            throw new Exception("old transacation still exists");
        // Give a long timeout on this transacation for debugging...
        _transacation = new TransactionScope(TransactionScopeOption.RequiresNew, TimeSpan.FromSeconds(60));   
    }

    [TearDown]
    public virtual void CleanupTest()
    {

        // Roll all the changes made during the test back.
        _transacation.Dispose();
        _transacation = null;
    }
}

Since the TestInitialize decorated methods on the base class are called before TestInitialize methods in derived class, you can even add some data to the database in your parent class' TestInitialize method.

A parent class might look like:

[TestFixture]
public class MyClassTests : TestBase
{
    [TestFixtureSetUp]
    public void InitializeUnit()
    {
            //Setup mocks...
    }

    [SetUp]
    public override void InitializeTest()
    {   
            base.InitializeTest();
            // Add test data to database
    }

    [Test]
    public void RealTest()
    {
            ...
    }
}
Scott Willeke
  • 8,884
  • 1
  • 40
  • 52
0

I use Sql Server Compact Edition and regenerate a new copy of the database each time (simply copying an initial database is fine) and if used in read only mode multiple tests can share the same database file.

There are a few gotchas, and programmability is not supported but it works well for the basics that I needed it for. It is also surprisingly fast.

ShuggyCoUk
  • 36,004
  • 6
  • 77
  • 101
  • I've done something similar to that in the past, but the database for this project is probably too large to detach and attach a new copy each time. – Eric Neunaber Feb 24 '09 at 15:33
  • well if the tests are read only on the db you only need to do it once. you'll serialize all your unit tests that depend on the db otherwise (unless you fancy multiple unit test environments) not to mention dealing with multiple users. – ShuggyCoUk Feb 24 '09 at 15:57
  • But it might just be that you can't really unit test the database layer, this happens, it's not the end of the world but is a shame – ShuggyCoUk Feb 24 '09 at 15:58