How to extend NUnit to support transaction rollback?
The code for this article you can download here.
I create some unit tests which should test functionality connected with databases. I know that there are a lot of posts about not to test against database but from my experience I think it is better than using Mocks instead of. What I want is to have an option to say that some of the test methods should rollback what they’ve change in DB. After some googling I found that NUnit can be extended. Unfortunately, information connected with this topic on NUnit web site is not enough but I found a nice article by Ben Hall.
I decide to implement an add-in that will support Rollback attribute and will execute the test under TransactionScope. For this purpose I created a new Dll which contains 3 classes. A RollbackAttributre class which doesn’t allow multiple and can be applied only on methods.
[sourcecode language="csharp"]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class RollbackAttribute : Attribute
{
}
[/sourcecode]
Further I created ExecuteTestTransactionScopeMethod whinc inherites from NUnitTestMethod class and overrides one of its Run methods. There I run the test into a TransactionScope.
[sourcecode language="csharp"]
public class ExecuteTestTransactionScopeMethod : NUnitTestMethod
{
public ExecuteTestTransactionScopeMethod(MethodInfo method) : base(method) { }
public override void Run(TestCaseResult testResult)
{
try
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
base.Run(testResult);
}
}
catch (TransactionException exception)
{
testResult.Failure(exception.Message, exception.StackTrace);
}
}
}
[/sourcecode]
Then I created a TransactionScopeAddin class which implements IAddin and ITestDecorator interfaces. Both interfaces belongs to NUnit.Core.Extensibility namespace. The first one is needed in order to note NUnit that this is an add-in and also I need it in order to be able to install my add-in. It is done implementing IAddin.Install method. As you can found in posts that I mentioned above NUnit can be extended in four different ways using Event listeners, Suite builders, Test case builders and Test decorators. I’ve decided to use a test decorator NUnit’s extension and that is why my class implements ITestDecorator. In Decorate method I try to find Rollback attribute if such exists I return a new instance of ExecuteTestTransactionScopeMethod class.
[sourcecode language="csharp"]
[NUnitAddin(Description = "Transaction Scope Addin", Type = ExtensionType.Core)]
public class TransactionScopeAddin : IAddin, ITestDecorator
{
#region IAddin Members
public bool Install(IExtensionHost host)
{
IExtensionPoint decorators = host.GetExtensionPoint(”TestDecorators”);
if (decorators == null)
{
return false;
}
decorators.Install(this);
return true;
}
#endregion
#region ITestDecorator Members
public NUnit.Core.Test Decorate(NUnit.Core.Test test, System.Reflection.MemberInfo member)
{
NUnitTestMethod nunitTestMethod = test as NUnitTestMethod;
if (nunitTestMethod != null)
{
Attribute ignore = Reflect.GetAttribute(member, “Ignore”, false);
if (ignore != null)
{
return test;
}
object[] attributes = member.GetCustomAttributes(typeof(RollbackAttribute), false);
foreach (var attribute in attributes)
{
RollbackAttribute ra = attribute as RollbackAttribute;
if (ra != null)
{
return new ExecuteTestTransactionScopeMethod(nunitTestMethod.Method);
}
}
}
return test;
}
#endregion
}
[/sourcecode]
I had some problems with testing this add-in because new version no always were taken into account from NUnit. It is just my feeling I’m not sure that the real problem was with NUnit. But according their specification I just should place my dlls into NUnit bin\addin directory.
After all was OK I received some exceptions about allowing network MSDTC access. After some investigation over the problem I found how to allow such access to DTC. Using Component Services console one can change DTC configuration. In order to allow network DTC access one should go to Component Services/Computers/My Computer context menu Properties.
Thin under MSDTC tab there is a button named Security Configuration. Go there and you will be able to configure network DTC access.
Below you can see how I configured my MSDTC in order to allow network access.
After some time I was using this add-in and Rollback attribute I can say that for some reason TransactionScope works unpredictable and sometimes some of the tests crashed with a transaction error. I’m not sure that it is directly connected with System.Transaction classes because I googled information that shows that such problems can be connected with NHibernate when we use TransactionScope with it. I’m about to do the same tests with MS Entity Framework and I will see if the same errors will occur with it.
But for our project where we use NHibernate I’ve decided to not use current add-in (for now) and I created two classes which allows us to test against database and keep it in an initial state. About this solution you can read in my next post.



November 3rd, 2008 at 6:15 pm
[...] my old post I explained how you can create a NUnit add-in for reverting changes in database made by unit tests. [...]
December 1st, 2008 at 2:09 pm
[...] How to extend NUnit to support transaction rollback? [...]