Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested TransactionScope for NUnit TestFixure and SetUp

I derive from this base class in order to enclose each indivdual test into a transaction that is rolled back

public abstract class TransactionBackedTest
{
    private TransactionScope _transactionScope;

    [SetUp]
    public void TransactionSetUp()
    {
        var transactionOptions = new TransactionOptions
        {
            IsolationLevel = IsolationLevel.ReadCommitted,
            Timeout = TransactionManager.MaximumTimeout
        };

        _transactionScope = new TransactionScope(TransactionScopeOption.Required, 
                                                 transactionOptions);
    }

    [TearDown]
    public void TransactionTearDown()
    {
        _transactionScope.Dispose();
    }
}

Using this I also tried to setup a TestFixure transaction the same way:

[TestFixture]
class Example: TransactionBackedTest
{

    private TransactionScope _transactionScopeFixure;


    [TestFixtureSetUp]
    public void Init()
    {
        var transactionOptions = new TransactionOptions
        {
            IsolationLevel = IsolationLevel.ReadCommitted,
            Timeout = TransactionManager.MaximumTimeout
        };

        _transactionScopeFixure = new TransactionScope(TransactionScopeOption.Required,
                                                       transactionOptions);


        SetupAllDataForAllTest();
    }

    [TestFixtureTearDown]
    public void FixtureTearDown()
    {
        _transactionScopeFixure.Dispose();
    }


    public void SetupAllDataForAllTest()
    {
        // Sql stuff here that will get undone from the TestFixtureTearDown scope dispose
    }


    [Test]
    public void DoSqlStuff1()
    {
        // Sql stuff here that will get undone from the TransactionBackedTest
    }

    [Test]
    public void DoSqlStuff2()
    {
        // Sql stuff here that will get undone from the TransactionBackedTest
    }
}

The idea being that SetupAllDataForAllTest is ran once at the beginning and inserts all the base data that tests rely on. This base data needs to be deleted/rolledback once the tests are complete.

I also want each test isolated so they cannot interfere with each other as well.

The issue I am having right now is that after the first test, it states the TestFixture transaction has been closed, even though I only wanted it to close the SetUp transaction. My assumption is that if you Dispose() and inner transaction it diposes the outer, so I am not sure how to accomplish what I want to do

like image 864
LearningJrDev Avatar asked Aug 31 '15 15:08

LearningJrDev


1 Answers

You didn't say what database you use.

In MS SQL Server if you BEGIN TRANSACTION inside another transaction (make them nested) and then ROLLBACK TRANSACTION inside the nested transaction, it will roll back everything (the whole outer transaction as well).

ROLLBACK TRANSACTION without a savepoint_name or transaction_name rolls back to the beginning of the transaction. When nesting transactions, this same statement rolls back all inner transactions to the outermost BEGIN TRANSACTION statement.

To be able to roll back only the inner nested transaction it should be started by SAVE TRANSACTION <name> with some name for the nested transaction. Then you can ROLLBACK <name> to roll back just the nested part.

If you are using some other database, it may behave differently in nested transactions.

I have no idea how to make your classes issue correct BEGIN or SAVE TRANSACTION SQL statements depending on whether the transaction is nested or not.

like image 159
Vladimir Baranov Avatar answered Oct 03 '22 08:10

Vladimir Baranov