danielwertheim

danielwertheim


notes from a passionate developer

Share


Sections


Tags


Disclaimer

This is a personal blog. The opinions expressed here represent my own and not those of my employer, nor current or previous. All content is published "as is", without warranty of any kind and I don't take any responsibility and can't be liable for any claims, damages or other liabilities that might be caused by the content.

NUnit call chain and sample usage

Been using xUnit for a long time now, and thought it was about time to revisit NUnit again, now that it is out in v3.0. Taking a step “back”. Back to the possibility of being able to use attributes for setup and teardown again. Being able to easily have assembly initialization. And do you know what? I LIKE IT! I like having simple attributes for assembly initialization. I like having attributes that enable me to control setup- and tear down behaviour. Of course, there’s also the option of using the constructor and/or IDisposable for those who want. So, with this said. Lets just have a quick peek at what point each construct “kicks in”, in the execution of one or more tests. Lets also look at a simple base class construct that can be used to hide the attributes away and possibly providing more semantic names.

How does the call chain look?

Lets start with the possibility of having assembly initialization and tear down by using SetupFixtureAttribute and IDisposable:

[SetUpFixture]
public class TestingAssembly : IDisposable
{
    public TestingAssembly() {
        WriteLine("In cTor");
    }

    public void Dispose() {
        WriteLine("In Dispose");
    }

    static void WriteLine(string value)
    {
        File.AppendAllText(
            @"D:Tempdump.txt",
            "TestingAssembly|" + value + Environment.NewLine);
    }
}

And in a “test-class”, you can make use the constructor and IDisposable as well as the attributes: SetupAttribute, OneTimeSetup, TearDown and OneTimeTearDown:

public class Testing1 : IDisposable
{
    public Testing1()
    {
        WriteLine("In cTor");
    }

    public void Dispose()
    {
        WriteLine("In Dispose");
    }

    [SetUp]
    public void Foo1()
    {
        WriteLine("In SetUp");
    }

    [OneTimeSetUp]
    public void Foo2()
    {
        WriteLine("OneTimeSetUp");
    }

    [OneTimeTearDown]
    public void Foo3()
    {
        WriteLine("OneTimeTearDown");
    }

    [TearDown]
    public void Foo4()
    {
        WriteLine("In TearDown");
    }

    [Test]
    public void Test1()
    {
        WriteLine("In test1");
    }

    [Test]
    public void Test2()
    {
        WriteLine("In test2");
    }

    static void WriteLine(string value)
    {
        File.AppendAllText(
            @"D:Tempdump.txt",
            "Testing1|" + value + Environment.NewLine);
    }
}
public class Testing2 : IDisposable
{
    public Testing2()
    {
        WriteLine("In cTor");
    }

    public void Dispose()
    {
        WriteLine("In Dispose");
    }

    [SetUp]
    public void Foo1()
    {
        WriteLine("In SetUp");
    }

    [OneTimeSetUp]
    public void Foo2()
    {
        WriteLine("OneTimeSetUp");
    }

    [OneTimeTearDown]
    public void Foo3()
    {
        WriteLine("OneTimeTearDown");
    }

    [TearDown]
    public void Foo4()
    {
        WriteLine("In TearDown");
    }

    [Test]
    public void Test1()
    {
        WriteLine("In test1");
    }

    [Test]
    public void Test2()
    {
        WriteLine("In test2");
    }

    static void WriteLine(string value)
    {
        File.AppendAllText(
            @"D:Tempdump.txt",
            "Testing2|" + value + Environment.NewLine);
    }
}

Result

The output of the above would be:

TestingAssembly|In cTor
Testing1|In cTor
Testing1|OneTimeSetUp
Testing1|In SetUp
Testing1|In test1
Testing1|In TearDown
Testing1|In SetUp
Testing1|In test2
Testing1|In TearDown
Testing1|OneTimeTearDown
Testing1|In Dispose
Testing2|In cTor
Testing2|OneTimeSetUp
Testing2|In SetUp
Testing2|In test1
Testing2|In TearDown
Testing2|In SetUp
Testing2|In test2
Testing2|In TearDown
Testing2|OneTimeTearDown
Testing2|In Dispose
TestingAssembly|In Dispose

Avoiding confusion

Most often, I actually do hide the usage of the attributes, by using a base-class, providing somewhat more semantic names (I think). That could be something like this:

public abstract class UnitTests
{
    [SetUp]
    [DebuggerStepThrough]
    protected virtual void OnBeforeEachTest() { }

    [TearDown]
    [DebuggerStepThrough]
    protected virtual void OnAfterEachTest() { }

    [OneTimeSetUp]
    [DebuggerStepThrough]
    protected virtual void OnBeforeAllTests() { }

    [OneTimeTearDown]
    [DebuggerStepThrough]
    protected virtual void OnAfterAllTests() { }
}

Summary

Mostly a post for myself to go somewhere when I need to remember. If useful for you as well, then…sweet.

Cheers,

//Daniel

View Comments