There has been mixed reaction to the removal of [SetUp] and [TearDown] in xUnit.net. Personally, I think it's great as it helps to raise unit test 'smells', particularly around how classes interact with each another. Here's a small example of how we can use the BeforeAfterTestAttribute in xUnit to remove duplicate code. (It's based on the security workaround I talked about yesterday.)
[SetUp]
[TearDown]
BeforeAfterTestAttribute
Instead of repeating three lines of code in each unit test to update the current identity, we can just define an attribute like [AssumeIdentity] that will take care of things for us. Here's the little fixture I wrote to test it.
[AssumeIdentity]
public class AssumeIdentityAttributeFixture { [Test] public void CallingSecuredMethodWillThrow() { Assert.Throws<SecurityException>(delegate { SecuredMethod(); }); } [Test, AssumeIdentity("Munchkin")] public void CallingSecuredMethodWithAssumedIdentityPasses() { Assert.DoesNotThrow(delegate { SecuredMethod(); }); } [PrincipalPermission(SecurityAction.Demand, Role = "Munchkin")] public void SecuredMethod() {} } public class AssumeIdentityAttribute : BeforeAfterTestAttribute { public AssumeIdentityAttribute(string name) { this.name = name; } public override void Before(MethodInfo methodUnderTest) { originalPrincipal = Thread.CurrentPrincipal; GenericIdentity identity = new GenericIdentity("boo"); GenericPrincipal principal = new GenericPrincipal(identity, new string[] { name }); Thread.CurrentPrincipal = principal; } public override void After(MethodInfo methodUnderTest) { Thread.CurrentPrincipal = originalPrincipal; } readonly string name; IPrincipal originalPrincipal; }
public class AssumeIdentityAttributeFixture { [Test] public void CallingSecuredMethodWillThrow() { Assert.Throws<SecurityException>(delegate { SecuredMethod(); }); }
[Test, AssumeIdentity("Munchkin")] public void CallingSecuredMethodWithAssumedIdentityPasses() { Assert.DoesNotThrow(delegate { SecuredMethod(); }); }
[PrincipalPermission(SecurityAction.Demand, Role = "Munchkin")] public void SecuredMethod() {} }
{ public AssumeIdentityAttribute(string name) { this.name = name; } public override void Before(MethodInfo methodUnderTest) { originalPrincipal = Thread.CurrentPrincipal; GenericIdentity identity = new GenericIdentity("boo"); GenericPrincipal principal = new GenericPrincipal(identity, new string[] { name }); Thread.CurrentPrincipal = principal; }
public override void After(MethodInfo methodUnderTest) { Thread.CurrentPrincipal = originalPrincipal; }
As you can see, before each test it executed, we update the current thread's identity, and then reset it after the test has run. It doesn't get much simpler than that :)