Click here to Skip to main content
15,879,535 members
Articles / Programming Languages / C#

Some Useful Concurrency Classes and A Small Testbench

Rate me:
Please Sign up or sign in to vote.
4.92/5 (37 votes)
15 Jan 2007CPOL70 min read 102.4K   1K   140  
Useful concurrency classes and small test bench in C#
using System;
// You will need this if you use the "ConditionalAttribute" attribute.
//using System.Diagnostics;

// Right now we are configured to use NUnit. Version 2.2 does most of the
// things we need.
using NUnit.Framework;

using MPFramework.AppCore.PlatformUtilities;

/// <summary>
/// <para>
/// The classes in this file demonstrate basic templates that we use for
/// Quality Assurance (QA) tests. The current preferred platform is Nunit.
/// We are not using our own testing mechanism anymore, but we still tend to
/// maintain the old QATester structure and that is illustrated here.
/// </para>
/// <para>
/// The classes demonstrate how we partition tests according to "level" and
/// "letter" and also explains our philosophy for the variegation.
/// </para>
/// </summary>
namespace MPFramework.AppCore.QualityAssurance
{
	/// <summary>
	/// <para>
	/// Sample container for common test data. This data is sometimes platform-specific.
	/// When it is, we like to decorate it (at least) with the "PlatformSpecific"
	/// attribute. We follow the naming convention "QATester_packageundertest_Testdata".
	/// "package" can be a class or namespace. We try to arrange things so that only
	/// the data is platform-specific. Otherwise, we need to use the PlatformSpecific
	/// attribute on testing methods themselves, which we generally like to avoid.
	/// </para>
	/// <para>
	/// Note: There is actually nothing platform-specific in this class. We are just
	/// demonstrating the use of the PlatformSpecific attribute.
	/// </para>
	/// </summary>
	//todo (KRM) A nice goal would be to create conditional compilation directives based
	// on platform, or perhaps an indexed array of platform-specific data??
	[PlatformSpecific(PlatformsSupported = CLRPlatformsSupported.MSWNT)]
	public static class QATester_QAUtils_Testdata
	{
		//// data for testing an Assert and an exception.
		/// <summary>
		/// Something we want to be true.
		/// </summary>
		static public readonly System.Boolean somethingTrue = true;
		/// <summary>
		/// Something we want to be false.
		/// </summary>
		static public readonly System.Boolean somethingFalse = false;

		//// data for our numerical tests.
		/// <summary>
		/// Correct output to test small calc against.
		/// </summary>
		static public readonly System.Int32 SmallCalcCorrectOutput = 2;
		/// <summary>
		/// Correct output to test big calc against.
		/// </summary>
		static public readonly System.Int32 BigCalcCorrectOutput = 3;
	}
	/// <summary>
	/// Tests are variegated according to "level" in our system. Level 0 tests
	/// typically just run a functions with default parameters to make it run quickly
	/// and check if it crashes. We do this so we can run all Level 0 tests first
	/// to see if we have basic reliability before we run longer tests. This is
	/// done this way because our system is very large with some fairly complicated
	/// tests that take a long time.
	/// Example:
	/// Level 0 tests for functions in QAUtils.
	/// </summary>
	[TestFixture]
	[Category(QAUtils.TestLevel0Name)]
	public class QATester_QAUtils_0
	{
		/// <summary>
		/// <summary>
		/// Obiligatory default constructor needed by almost anybody's test executive.
		/// </summary>
		/// </summary>
		public QATester_QAUtils_0() { }
		/// <summary>
		/// Simple test of just a testing method (what else?).
		/// </summary>
		[Test(Description = "Level 0 series a tests for QAUtils")]
		public void QATester_RunTest_a()
		{
			// Just exercise an NUint feature.
			Assert.AreNotEqual(QATester_QAUtils_Testdata.somethingFalse,
				QATester_QAUtils_Testdata.somethingTrue, "Basic 0a");
		}
		/// <summary>
		/// Slightly more complicated test of our old exception-testing style.
		/// We sometimes split up tests into series when we have a large number
		/// for a package.
		/// </summary>
		/// <remarks>
		/// Originally we partitioned tests a,b,c, etc. on different machines for the
		/// larger tests. Our reflection-based tester did this based on the "_a, _b",
		/// etc. suffixes. We haven't figured out a way to do this with NUnint yet.
		/// Comments/help, anyone??
		/// </remarks>
		[Test(Description = "Level 0 series b tests for QAUtils")]
		public void QATester_RunTest_b()
		{
			// This is our old exception-testing style. We still prefer it sometimes
			// because NUnit stops when a method throws an exception, so we can't
			// put any tests after it and expect it to keep going.
			try {
				DemoHelper.ThrowException();
				Assert.Fail("ThrowException() 0b - no exception");
			}
			catch {
			}
		}
	}
	/// <summary>
	/// This is a "level 1" test. It has "first level" real operations in it.
	/// These are things that generally don't take an extremely long time, but
	/// are more then just "crash testing".
	/// </summary>
	[TestFixture]
	[Category(QAUtils.TestLevel1Name)]
	public class QATester_QAUtils_1
	{
		/// <summary>
		/// The obligatory default constructor. 
		/// </summary>
		public QATester_QAUtils_1() { }
		/// <summary>
		/// Test of a computational method.
		/// </summary>
		// We can use a conditional statement if we don't want to move all tests
		// to a separate assembly, but still want to eliminate tests from a build.
		// This doesn't help with any static test data, though.
		//[Conditional("QATESTS_ON")]
		[Test(Description = "Level 1 series a tests for QAUtils")]
		public void QATester_RunTest_DoASmallCalculation_a()
		{
			int output = DemoHelper.DoASmallCalculation();
			Assert.AreEqual(QATester_QAUtils_Testdata.SmallCalcCorrectOutput,
				output, "DoASmallCalculation() 1a");
		}
		/// <summary>
		/// Test of a computational method. This could be a different test run on
		/// another machine under our old scheme. The test engine could be programmed
		/// to recognize a vs. b. When we need distributed tests again, we'll
		/// figure out some way to do it in NUnint, maybe :-)
		/// </summary>
		// We can use a conditional statement if we don't want to move all tests
		// to a separate assembly, but still want to eliminate tests from a build.
		// This doesn't help with any static test data, though.
		//[Conditional("QATESTS_ON")]
		[Test(Description = "Level 1 series b tests for QAUtils")]
		public void QATester_RunTest_DoASmallCalculation_b()
		{
			int output = DemoHelper.DoASmallCalculation();
			Assert.AreEqual(QATester_QAUtils_Testdata.SmallCalcCorrectOutput,
				output, "DoASmallCalculation() 1b");
		}
	}
	/// <summary>
	/// This is a "level 2" test. It does testing that is more computationally
	/// intensive then level 1. There can be level 3, 4...  - you get the idea.
	/// </summary>
	[TestFixture]
	[Category(QAUtils.TestLevel1Name)]
	public class QATester_QAUtils_2
	{
		/// <summary>
		/// The obligatory default constructor. 
		/// </summary>
		public QATester_QAUtils_2() { }
		/// <summary>
		/// Test of a more intensive computational method.
		/// </summary>
		[Test(Description = "Level 2 series a tests for QAUtils")]
		public void QATester_RunTest_DoABigCalculation_a()
		{
			int output = DemoHelper.DoABigCalculation();
			Assert.AreEqual(QATester_QAUtils_Testdata.BigCalcCorrectOutput,
				output, "DoABigCalculation() 2a");
		}
	}
	/// <summary>
	/// Just some little methods to demo our QATests......
	/// </summary>
	internal static class DemoHelper
	{
		public static void ThrowException()
		{ throw new System.Exception(); }
		public static int DoASmallCalculation()
		{ return 1 + 1; }
		public static int DoABigCalculation()
		{ return 1 + 1 + 1; }
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
Kurt R. Matis received the B.S degree in Applied Mathemetics from Empire State College in 1981 and the PhD. degree in Electrical Engineering from Rensselaer Polytechnic Institute in 1984. He has been involved in several companies over the past 30 years, but has been most recently involved with the Macher-Plander Software Engineering Consortium, of which he is a co-founder. The Consortium is involved with education in .Net technologies and Software Quality Management topics.

Dr. Matis is a member of IEEE and the American Historical Truck Society. Kurt lives happily in Troy, NY with his beautiful wife, two beautiful daughters and his beautiful trucks.

Dr. Matis is interested in working with companies who wish assistance in porting legacy applications of all types to .Net. He can be reached at krogerma@aol.com.




Comments and Discussions