Share via


Weaving with xUnit.net

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.)

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.

 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; 
} 

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 :)