5. Advanced Options

5.1. Additional Attributes

There are several options available beyond the basic [Test] attribute. This section will provide an overview of these options.

5.1.1. Test Properties

Category

It's often handy to categorize a Test. This can be done using the Category feature. Within the Zanebug GUI, this allows Tests to be filtered, sorted, etc. by category.

using System;
using Adapdev.UnitTest;

namespace Examples.Zanebug
{
	[TestFixture]
	public class Attributes
	{

		// A Test with a Category
		[Test(Category="Some Category")]
		public void TestWithCategory()
		{
			Console.WriteLine("Test with category");
		}

	}
}

5.1.2. SetUp and TearDown

Both TestFixtures and Tests can have custom code run at the beginning and the end of their iterations. This is quite useful in instances where you need to setup database information, prepare a resource, etc. and then restore it to its previous state when the testing is done. A typical example would be the following scenario:

using System;
using Adapdev.UnitTest;

namespace Examples.Zanebug
{
	[TestFixture]
	public class Attributes
	{

		// Runs once at the beginning of the TestFixture
		[TestFixtureSetUp]
		public void TestFixtureSetUp()
		{
			// insert test records into database
		}

		// A Test
		[Test]
		public void SimpleTest()
		{
			// test code
		}

		// Runs once at the end of the TestFixture
		[TestFixtureTearDown]
		public void TestFixtureTearDown()
		{
			// remove test records from database
		}

	}
}

In the above example, setup and teardown operations are done each time the TestFixture runs. The same can be done at the Test level. It's even possible to run setup and teardown operations only for specific Tests.

List below are the various setup and teardown attributes:

Setup

  • TestFixtureSetUp

  • TestSetUp

  • SetUp (same as TestSetUp - provided for NUnit compatability)

TearDown

  • TestFixtureTearDown

  • TestTearDown

  • TearDown (same as TestTearDown - provided for NUnit compatability)

See the API for full documentation

Test Specific SetUp and Teardown

When a SetUp or TearDown operation should only be performed for a specific Test, then the Test property should be used:

using System;
using Adapdev.UnitTest;

namespace Examples.Zanebug
{
	[TestFixture]
	public class Attributes
	{

		// Runs once at the beginning of SimpleTest only
		[TestSetUp("SimpleTest")]
		public void SpecificTestSetUp()
		{
			// setup code
		}

		// A Test
		[Test]
		public void SimpleTest()
		{
			// test code
		}

		// Runs once at the end of SimpleTest only
		[TestTearDown("SimpleTest")]
		public void SpecificTestTearDown()
		{
			// teardown code
		}
	}
}

5.1.3. ExpectedException

Often times tests are written that expect an error to occur. For example, if you have a method called Divide(int a, int b), and you pass in a 0, you would expected a DivideByZeroException. Proper testing would validate that this error is thrown. In order to do this, the ExpectedException attribute should be used:

using System;
using Adapdev.UnitTest;

namespace Examples.Zanebug
{
	[TestFixture]
	public class Attributes
	{
		[Test]
		[ExpectedException(typeof(DivideByZeroException))]
		public void ExpectedDivideByZeroException()
		{
			MyMath.Divide(12,0); // throws DivideByZeroException
		}
	}
}

In the above example, the Test expects a DivideByZeroException to be thrown. If the exception is thrown, the test passes. If it isn't thrown, the test fails.

Note

The test will pass if the expected exception is thrown, or an exception that inherits from it (i.e. a child class). For instance, if the above example expected an exception type of Exception, then the Test would still pass since DivideByZeroException is a subclass of Exception.

5.1.4. Ignore

It is possible to ignore tests at run-time. For example, you may have a lengthy, resource intesive test that you only need to run occassionaly. You can mark the Test with Ignore, and it won't be run. If you want to run it at a later period, you simply remove the Ignore attribute. This allows you to maintain the Test code without having to always run it. You can optionally provide a reason why the test is being ignored, which will be displayed at run-time.

Within the Zanebug GUI, you can override the Ignore attribute by checking a Test. When the TestSuite first loads, all Tests marked with Ignore will not be checked. They can be checked at any time if you decide to run them. Likewise, you can impose the Ignore attribute on Tests at run-time by unchecking them in the GUI.

using System;
using Adapdev.UnitTest;

namespace Examples.Zanebug
{
	[TestFixture]
	public class Attributes
	{
		[Test]
		[Ignore]
		public void SimpleTest1()
		{
			//test code
		}
		
		[Test]
		[Ignore("Some reason")]
		public void SimpleTest2()
		{
			//test code
		}

	}
}

5.1.5. MaxKMemory

When it's required that an operation only consume a certain amount of memory, then the MaxKMemory attribute should be used. This specifies how much memory should be used, and anything above that will fail.

using System;
using Adapdev.UnitTest;

namespace Examples.Zanebug
{
	[TestFixture]
	public class Attributes
	{
		[Test]
		[MaxKMemory(200)]
		public void SimpleTest()
		{
			//test code
			//if this test consumes more than 200kb of memory
			//then it will fail
		}
		
	}
}

Warning

This is a beta feature at this point, and is not guaranteed to perform accurately (discrepancies have been noticed with the memory measurement feature).

5.1.6. MinOperationsPerSecond

Performance-based testing often measures the speed at which an operation occurs. When it's necessary to ensure that a certain level of performance can be attained, the MinOperationsPerSecond attribute should be used.

The Zanebug engine measures the execution time for a Test, and then determines how many times that Test can be run within a second.

Note

The test engine introduces a small amount of overhead via Reflection, which should be taken into account

Note

Due to initialization overhead, the Test will always perform slower the first time. Therefore, it is recommended that a Test be performed more than once after being loaded in order to get a better idea of its performance

using System;
using Adapdev.UnitTest;

namespace Examples.Zanebug
{
	[TestFixture]
	public class Attributes
	{

		// A Test that will fail if it can't be repeated
		// the min number of times in a second
		[Test]
		[MinOperationsPerSecond(1000)]
		public void MinOperationsPerSecond()
		{
			// if this test can not be repeated 1000 times within a second
			// it fails
		}

	}
}

5.1.7. Repeat

Tests must often be repeated in succession to measure things such as average performance, concurrency issues, etc. This can be accomplished with the Repeat attribute

using System;
using Adapdev.UnitTest;

namespace Examples.Zanebug
{
	[TestFixture]
	public class Attributes
	{

		// A Test that is repeated a set number of times
		[Test]
		[Repeat(5)]
		public void Repeat()
		{
			// test code
		}

		// A Test that is repeated a set number of times
		// with a 3 second delay in between
		[Test]
		[Repeat(5,3000)]
		public void RepeatWithDelay()
		{
			// test code
		}
	}
}