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