Seamless transaction control for MSTest code
Tags: programming, transactions, dotnet, mstest
Published: 2021-09-10 13:56:36

---
title: Seamless transaction control for MSTest code 
published: true
description: Covering a legacy system with tests is always an interesting task. Let's take a look at one way to introduce transaction control &hellip; Continue reading &#8220;Transaction control for LINQ to SQL repositories&#8221;
tags: #programming, #transactions, #dotnet, #mstest
canonical_url: https://blog.wiseowls.co.nz/index.php/2018/08/09/transaction-control-linq-to-sql-repositories/
cover_image: 
---

Covering a legacy system with tests is always an interesting task:

**10** You want as much of your codebase covered before you are confident enough to start changing the system itself,
**20** but you can not mock out external dependencies such as databases without touching too much code…
**30** GOTO **10**

## Okay, how do we break out of this loop?

One way to do so would be to not mock the database out: just have your tests [clean up after themselves](https://stackoverflow.com/questions/3537972/doing-a-rollback-repository-integration-tests). Easy, right?

```csharp
[TestClass]
public class Testing {
  [TestInitialise]
  public void Init() {
      var tran = new ScopedTransaction();
    }
    [TestMethod]
  public void Test() {
    using(var db = new DbContext()) {
      db.ExecuteCommand("DELETE FROM tblEmployee;");
    }
  }
}
```

Kind of. What if at some point we’d like to have one test in a class commit something?
I guess we could save transaction handle as a field and refer back to it. But I still feel transaction control should not be part of `TestInitialise` routine – we’re not exactly setting up tests here, we’re setting up the environment itself. And having to define a decorated method everywhere we need this trick seems repetitive. So, is there a cleaner way of doing it that does not clutter our Init() method and still does the job?

## A quick peek into **TestMethodAttribute** reveals – there actually is

```csharp
using System;

namespace Microsoft.VisualStudio.TestTools.UnitTesting {
  ///

  The test method attribute.

  [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
  public class TestMethodAttribute: Attribute {
    ///

    Executes a test method.

    ///The test method to execute. /// An array of TestResult objects that represent the outcome(s) of the test.
    /// Extensions can override this method to customize running a TestMethod.
    public virtual TestResult[] Execute(ITestMethod testMethod) {
      return new TestResult[1] {
        testMethod.Invoke((object[]) null)
      };
    }
  }
}
```

Turns out Microsoft have thoughtfully made `TestMethodAttribute.Execute` virtual meaning we can override it should we be inclined to do so:

```csharp
[AttributeUsage(AttributeTargets.Method)]
public class TransactionTestMethodAttribute: TestMethodAttribute {
  ///

  Executes a test method.Wrapped in Transaction Scope.In the end the thansaction gets discarded effectively rolling eveything back

  ///The test method to execute. /// An array of TestResult objects that represent the outcome(s) of the test.
  public override TestResult[] Execute(ITestMethod testMethod) {
    using(new TransactionScope())
    return base.Execute(testMethod);
  }
}
```

With above test attribute our tests look a bit better now:

```csharp
[TestClass]
public class Testing {
  [TransactionTestMethodAttribute]
  public void Test() {
    using(var db = new DbContext()) {
      db.ExecuteCommand("DELETE FROM tblEmployee;"); //that's it folks, everyone is fired
    }
  }
}
```

## We can take it a step further

and have other actions wrap around our tests. For example, we opted to temporarily disable all triggers in the database, well, because we could:

```csharp
[AttributeUsage(AttributeTargets.Method)]
public class NoTriggersTransactionTestMethodAttribute: TransactionTestMethodAttribute {
    ///
    ///

    Executes a test method.Against a database with disabled triggers

    ///The test method to execute. /// An array of TestResult objects that represent the outcome(s) of the test.
    public override TestResult[] Execute(ITestMethod testMethod) {
      var db = new DbContext(); //no using(dbcontext) here in favor of try..finally
      try {
        db.ExecuteCommand("sp_msforeachtable 'ALTER TABLE ? DISABLE TRIGGER all'");
        return base.Execute(testMethod);
      } finally {
        db.ExecuteCommand("sp_msforeachtable 'ALTER TABLE ? ENABLE TRIGGER all'");
        db.Dispose(); //note we need to call this, as we opted to not go for c# using(dbcontext) syntax
      }
    }
```