Nesting ambient transactions.. doable?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

im trying to put a transaction around my NUnit tests fixtures and a seperate
transaction around each test and I'm trying to do that in my base class so
that all my test can benefit from them.

The problem is that I can't find a way to do both transactions. it's either
around the whole fixture or around the test. is there a way to do both?

here is my base test class:

using System;
using System.Transactions;
using NUnit.Framework;

namespace Library.Tests
{
public enum TestTransactionMode
{
None,
AroundFixture,
AroundTests
}


[TestFixture]
public abstract class BaseFixtureWithTxRollback : BaseFixture
{
Transaction fixtureTransaction;
Transaction testTransaction;

private TestTransactionMode testTransactionMode =
TestTransactionMode.AroundFixture;

/// <summary>
/// The transaction mode of the test
/// </summary>
public TestTransactionMode TestTransactionMode
{
get { return testTransactionMode; }
set { testTransactionMode = value; }
}

[TestFixtureSetUp]
public override void TestFixtureSetUp()
{
base.TestFixtureSetUp();

if (testTransactionMode == TestTransactionMode.AroundFixture)
{
fixtureTransaction = new CommittableTransaction();
Transaction.Current = fixtureTransaction;
}
}

[TestFixtureTearDown]
public override void TestFixtureTearDown()
{
if (fixtureTransaction != null)
{
fixtureTransaction.Rollback();
}
}

[SetUp]
public override void TestSetUp()
{
base.TestSetUp();

if (testTransactionMode == TestTransactionMode.AroundTests)
{
testTransaction = new CommittableTransaction();
Transaction.Current = testTransaction;
}
}

[TearDown]
public override void TestTearDown()
{
base.TestTearDown();

if (testTransaction != null)
{
testTransaction.Rollback();
}
}
}
}

So basically i want to have another
TestTransactionMode.AroundTestAndFixture. I found SubordinateTransaction
class which takes ISimpleTransactionSuperior in its constructor but there is
no implementation for this interface.
 
Look at the book Test Driven Development in .NET. It has a neat way of
handling this issue with base classes. It does not nest .NET transactions,
however. The concept is to pull all work for a single TestFixture on the same
transaction, no matter where it occurs in the class. Very neat way of rolling
back database work after testing.

There are issues with transactions nested in code, largely due to SQL Server
isolation levels. This may be different for other databases, but lock
escalation could create deadlocks if you are testing load on the same
database you are testing your unit tests (yes, I know it is a bad practice,
but it does sometimes happen).

If you still desire to nest transactions, be sure to explicitly name each
one so multiple transactions on a single connection object can be committed
or rolled back independently.

SqlTransaction outerTransaction = connection.BeginTransaction("outer");

Apologies for not escavating the code and providing specific guidance. :-)

--
Gregory A. Beamer
MVP; MCP: +I, SE, SD, DBA

***************************
Think Outside the Box!
***************************


eacsub said:
im trying to put a transaction around my NUnit tests fixtures and a seperate
transaction around each test and I'm trying to do that in my base class so
that all my test can benefit from them.

The problem is that I can't find a way to do both transactions. it's either
around the whole fixture or around the test. is there a way to do both?

here is my base test class:

using System;
using System.Transactions;
using NUnit.Framework;

namespace Library.Tests
{
public enum TestTransactionMode
{
None,
AroundFixture,
AroundTests
}


[TestFixture]
public abstract class BaseFixtureWithTxRollback : BaseFixture
{
Transaction fixtureTransaction;
Transaction testTransaction;

private TestTransactionMode testTransactionMode =
TestTransactionMode.AroundFixture;

/// <summary>
/// The transaction mode of the test
/// </summary>
public TestTransactionMode TestTransactionMode
{
get { return testTransactionMode; }
set { testTransactionMode = value; }
}

[TestFixtureSetUp]
public override void TestFixtureSetUp()
{
base.TestFixtureSetUp();

if (testTransactionMode == TestTransactionMode.AroundFixture)
{
fixtureTransaction = new CommittableTransaction();
Transaction.Current = fixtureTransaction;
}
}

[TestFixtureTearDown]
public override void TestFixtureTearDown()
{
if (fixtureTransaction != null)
{
fixtureTransaction.Rollback();
}
}

[SetUp]
public override void TestSetUp()
{
base.TestSetUp();

if (testTransactionMode == TestTransactionMode.AroundTests)
{
testTransaction = new CommittableTransaction();
Transaction.Current = testTransaction;
}
}

[TearDown]
public override void TestTearDown()
{
base.TestTearDown();

if (testTransaction != null)
{
testTransaction.Rollback();
}
}
}
}

So basically i want to have another
TestTransactionMode.AroundTestAndFixture. I found SubordinateTransaction
class which takes ISimpleTransactionSuperior in its constructor but there is
no implementation for this interface.
 
I'm not sure what you mean by "pulling all work for a single TestFixture" but
i think that's what i'm doing by assigning a new commitable transaction to
Transaction.Current in the [TestFixtureSetup]. You're maybe right regarding
deadlocks, but it's needed to seperate the tests from each other in their own
transaction so that they don't conflic with each other.
 
Back
Top