Integration Tests – Tests Fail When Network Unavailable

I code a lot whilst travelling to work on the train. One thing that has bugged me is integration tests that rely on remote services will fail unless I’ve tethered my phone. Having those few red tests littering my test results kind of irks me and leads me to run the tests less often or not at all.

What I wanted was an ignore attribute that could detect if the network was unavailable and ignore the test, but I couldn’t find anythign to suit. As there isn’t great support for extending test attributes, I decided to build support in to my IntergrationBaseTest class.

This could have been solved easily by placing these two lines at the start of my test:

            
           if(!NetworkInterface.GetIsNetworkAvailable())
                Assert.Inconclusive();

The above is simple but I wanted to explore the idea of custom test attributes to see what I could come up with.

What first sprang to mind was ASP.NET MVC’s ActionFilterAttributes. MSDN describes ActionFilterAttributes as the following:

ActionFilterAttribute is an abstract class that has four virtual methods that you can override: OnActionExecuting, OnActionExecuted, OnResultExecuting, and OnResultExecuted.

The ASP.NET MVC framework will call the OnActionExecuting method of your action filter before it calls any action method that is marked with your action filter attribute. Similarly, the framework will call the OnActionExecuted method after the action method has finished.

Taking this approach and applying it to MSTest I created the below abstract attribute:

  
    public abstract class CustomTestAttribute : Attribute
    {
        public virtual void OnTestExecuting(TestContext context) {}
        public virtual void OnTestExecuted(TestContext context) {}
    }

I marked the methods as virtual so as not to force derived classes to implement both. As you might have guessed the OnTestExecuting maps to methods marked with the TestInitializeAttribute and the OnTestExecuted maps to the TestCleanupAttribute in MSTest. The benefit we gain here is the ability to descriminate down to the method level within a class.

To support the new attribute the base class is going to have to know about it and execute the respective methods in the corresponding initialize and cleanup methods.

First, to deal with multiple attributes as a single unit, I created a CompositeTestAttribute, deriving form the CustomTestAttribute:

  
    public sealed class CompositeTestAttribute : CustomTestAttribute
    {
        private readonly IEnumerable<CustomTestAttribute> attributes;

        public CompositeTestAttribute(IEnumerable<CustomTestAttribute> attributes)
        {
            this.attributes = attributes;
        }

        public override void OnTestExecuting(TestContext context)
        {
            foreach (var customTestAttribute in attributes)
            {
                customTestAttribute.OnTestExecuting(context);
            }
        }

        public override void OnTestExecuted(TestContext context)
        {
            foreach (var customTestAttribute in attributes)
            {
                customTestAttribute.OnTestExecuting(context);
            }
        }
    }

To determine which attributes the executing test is decorated with we can use the TestContext which gets injected by mstest at runtime, all you need to do is dangle a property on the base class:

  
	public TestContext TestContext { get; set; }

Using the TestContext we can access the “FullyQualifiedTestClassName” and “TestName” properties. This gives us enough information to generate a type and access the attributes:

  
        private IEnumerable<CustomTestAttribute> GetCustomTestAttributes()
        {
            IEnumerable<CustomTestAttribute> attributes = Enumerable.Empty<CustomTestAttribute>();
            string className = TestContext.FullyQualifiedTestClassName;
            string methodName = TestContext.TestName;

            Type testClassType = Type.GetType(className);
            if (testClassType != null)
            {
                MemberInfo mi = testClassType.GetMethod(methodName);
                attributes = mi.GetCustomAttributes<CustomTestAttribute>();
            }

            return attributes;
        }

All that’s needed now is to invoke OnTestExecuting and OnTestExecuted in the TestInitialize and TestCleanup methods respectively.

  
        [TestInitialize()]
        public void MyTestInitialize()
        {
            new CompositeTestAttribute(GetCustomTestAttributes())
                .OnTestExecuting(this.TestContext);
        }

        [TestCleanup()]
        public void MyTestCleanup()
        {
            new CompositeTestAttribute(GetCustomTestAttributes())
                .OnTestExecuted(this.TestContext);
        }

Now, that the infrastucture is there, we can start implementing CustomTestAttributes. Which brings me back to the reason for all this.
To determine if the Network is available, there is a handy helper method located in “System.Net.NetworkInformation.NetworkInterface” called

“GetIsNetworkAvailable()”

  
    public class IgnoreWhenNetworkUnavailableAttribute : CustomTestAttribute
    {
        public override void OnTestExecuting(TestContext context)
        {
            if(!NetworkInterface.GetIsNetworkAvailable())
                Assert.Inconclusive();
        }
    }

Now to make use of this, all we have todo is derive from the IntegrationBaseTest and decorate our network dependent test methods. 🙂

For clarity, below is the full code. Although this could have been achieved by far simpler means, it was an interesting exercise, that allowed me to delve into some code and have a little fun. I hope you find this helpful and put CustomTestAttributes to use in scenarios I haven’t thought of.

  
 /// <summary>
    /// Summary description for IntegrationTestBase
    /// </summary>
    [TestClass]
    public class IntegrationTestBase
    {
	public TestContext TestContext { get; set; }

        [TestInitialize()]
        public void MyTestInitialize()
        {
            new CompositeTestAttribute(GetCustomTestAttributes())
                .OnTestExecuting(this.TestContext);
        }

        [TestCleanup()]
        public void MyTestCleanup()
        {
            new CompositeTestAttribute(GetCustomTestAttributes())
                .OnTestExecuted(this.TestContext);
        }

        private IEnumerable<CustomTestAttribute> GetCustomTestAttributes()
        {
            IEnumerable<CustomTestAttribute> attributes = Enumerable.Empty<CustomTestAttribute>();
            string className = TestContext.FullyQualifiedTestClassName;
            string methodName = TestContext.TestName;

            Type testClassType = Type.GetType(className);
            if (testClassType != null)
            {
                MemberInfo mi = testClassType.GetMethod(methodName);
                attributes = mi.GetCustomAttributes<CustomTestAttribute>();
            }

            return attributes;
        }
    }

    public class IgnoreWhenNetworkUnavailableAttribute : CustomTestAttribute
    {
        public override void OnTestExecuting(TestContext context)
        {
            if(!NetworkInterface.GetIsNetworkAvailable())
                Assert.Inconclusive();
        }
    }

    public abstract class CustomTestAttribute : Attribute
    {
        public virtual void OnTestExecuting(TestContext context) {}
        public virtual void OnTestExecuted(TestContext context) {}
    }

    public sealed class CompositeTestAttribute : CustomTestAttribute
    {
        private readonly IEnumerable<CustomTestAttribute> attributes;

        public CompositeTestAttribute(IEnumerable<CustomTestAttribute> attributes)
        {
            this.attributes = attributes;
        }

        public override void OnTestExecuting(TestContext context)
        {
            foreach (var customTestAttribute in attributes)
            {
                customTestAttribute.OnTestExecuting(context);
            }
        }

        public override void OnTestExecuted(TestContext context)
        {
            foreach (var customTestAttribute in attributes)
            {
                customTestAttribute.OnTestExecuting(context);
            }
        }
    }

Windows Azure Discovery Day

Just got back from Windows Azure Discovery Day with Graham Elliot. Overall a good day, covering Cloud Computing Scenarios for ISVs, Understanding the Windows Azure Platform Pricing Model, Building Applications for Windows Azure & SQL Azure, then finishing off with a few demo’s.

Useful Azure links:

Fabrikam Shipping Demo

Windows Azure SDK

Windows Azure Developer Training Kit

Cloud Cover | Channel 9

Microsoft Platform Ready

Get amongst it!