NUnit and the new TestContext Class

By | October 5, 2010

With release 2.5.7, NUnit has introduced a new TestContext class that can be used to get information about the tests that are running. No immediate applications of this jump out to me right now, but it’s good to know that the functionality is now available with resorting to hack-like approaches. This post is a bare bones introduction to the new, currently undocumented functionality.

 

Test Name

This little gem allows you to pull down the name of the test that was last executed. This information is available in both the setup and teardown methods as well. This can be demonstrated with the below test code.

[SetUp]
public void TestSetup()
{
    Console.WriteLine("setting up test: {0}", TestContext.TestName);
}

[TearDown]
public void TestTearDown()
{
    Console.WriteLine("tearing down test: {0}", TestContext.TestName);
}

[Test]        
public void TestNameTest()
{                        
    Assert.That(TestContext.TestName, Is.EqualTo("TestNameTest"));
}

 

Running this code in the NUnit test runner produces a green light and the following output.

testName

The TestContext class does just what it says: presents information based on the current context. Since the SetUp and TearDown methods are executing on behalf of the test TestNameTest, it knows to return that as the test name.

 

Test Status

The TestContext class also gives us information about the status of the test that is current in our given context. To demonstrate, we can modify our code as shown below.

[SetUp]
public void TestSetup()
{
    Console.WriteLine("setting up test: {0}, status {1}", 
        TestContext.TestName,
        TestContext.Status);
}

[TearDown]
public void TestTearDown()
{
    Console.WriteLine("tearing down test: {0}, status {1}", 
        TestContext.TestName, 
        TestContext.Status);
}

[Test]        
public void TestNameTest()
{                        
    Assert.That(TestContext.TestName, 
        Is.EqualTo("TestNameTest"));
}

 

Running this code in the NUnit test runner produces the below output.

testStatus

So again we can see that the TestContext returns information about the currently contextual test accurately – its status is inconclusive during setup, and changes to passed during teardown. The Status property is of type TestStatus, which is defined below (as taken from the NUnit source).

public enum TestStatus
{
    /// <summary>
    /// The test was inconclusive
    /// </summary>
    Inconclusive = 0,

    /// <summary>
    /// The test has skipped 
    /// </summary>
    Skipped = 1,

    /// <summary>
    /// The test succeeded
    /// </summary>
    Passed = 2,

    /// <summary>
    /// The test failed
    /// </summary>
    Failed = 3
}

 

Test Properties

The final little nugget is the ability to pull out what attributes are defined for a given test. Take the “test” below.

[Test]
[Property("prop1", "prop1value")]
[Property("prop2", "prop2value")]
public void SomePropertiesTest()
{
    foreach (string key in TestContext.Properties.Keys)
    {
        Console.WriteLine("{0}: {1}", key, TestContext.Properties[key]);
    }
}

 

This test produces the following output.

testProperties

 

Note the funky property called “_CATEGORIES”. NUnit treats a test’s defined categories as properties, and as such any use of TestContext’s Properties property will include this category list as one of the test’s properties.

 

One Final Note…

I’m an avid fan of TestDriven.NET; however, you’ll note that in the above examples I used NUnit’s test runner. This is because the TestContext class doesn’t work when the tests are run from TestDriven.NET; they all fail whenever trying to access a TestContext property with the below error.

tdnFailure

 

A couple of clues as to why this happens can be gleaned by looking at NUnit’s source. First, the TestName property.

public static string TestName
{
    get
    {
        return Context["TestName"] as string;
    }
}

 

Then, the Context property.

private static IDictionary _context;

private static IDictionary Context
{
    get
    {
        if (_context == null)
            _context = (IDictionary)CallContext.GetData(contextKey);

        return _context;
    }
}

 

CallContext is a static class that lives in the System.Runtime.Remoting.Messaging namespace. Without deep-diving, my guess would be that when tests are executed by TestDriven.NET from within the IDE, some mechanism that the CallContext class requires isn’t firing, resulting in the _context being set to null, which then results in our dandy object reference not set exception. Figuring out exactly why is the stuff of another post; the moral of the story is that if you want to use the CallContext class in your tests, you can’t expect said tests to pass when run from within the IDE using TestDriven.NET.