Roy Osherove's (ISerializable) has come up with a new RollBackAttribute to automatically rollback transaction for each test case. This is pretty neat because you can write things like:
[TestFixture]
public class Test
{
[Test,RollBack]
public void SomeTestWithDatabase()
{
// all what we do here
// is automatically rolled back
}
}
MbUnit implementation
Roy was kind enough to send me the source code of this attribute so I integrated it into MbUnit. Roy plans to make an article about the details of the implementations so I will not discuss it further. The interresting point is that the integration was done in less than 5 minutes, thanks to the extensibility of MbUnit.
Here is a part of the implementation of the attribute (I have stripped out the Service related code):
[AttributeUsage(AttributeTargets.Method,AllowMultiple=false,Inherited=true)]
public sealed class RollBackAttribute : DecoratorPatternAttribute
{
public override IRunInvoker GetInvoker(IRunInvoker invoker)
{
return new RollbackRunInvoker(invoker);
}
private class RollbackRunInvoker : DecoratorRunInvoker
{
public RollbackRunInvoker(IRunInvoker invoker)
:base(invoker){}
public override object Execute(object o, System.Collections.IList args)
{
EnterServicedDomain();
try
{
Object result = this.Invoker.Execute(o,args);
return result;
}
finally
{
AbortRunningTransaction();
LeaveServicedDomain();
}
}
#region Service stuff
private void AbortRunningTransaction()
{...}
private void LeaveServicedDomain()
{...}
private void EnterServicedDomain()
{...}
#endregion
}
}
There are a few things to say in the above implementation:
- DecoratorPatternAttribute is an abstract attribute for test case decorators, such as ExpectedException, Ignore, etc... The purpose of the attribute is to return a IRunInvoker implementation that acts as a wrapper around another IRunInvoker,
- This filter effect can be seen in the RollbackRunInvoker.Execute method, where the actual Test case method is called inside a Try/Catch statement. This guard is used to roll back transactions.