namespace NUnit.Framework { using System; using System.Collections; using System.Reflection; /// A TestSuite is a Composite of Tests. /// It runs a collection of test cases. Here is an example using /// the dynamic test definition. /// /// TestSuite suite= new TestSuite(); /// suite.AddTest(new MathTest("TestAdd")); /// suite.AddTest(new MathTest("TestDivideByZero")); /// /// Alternatively, a TestSuite can extract the Tests to be run automatically. /// To do so you pass the class of your TestCase class to the /// TestSuite constructor. /// /// TestSuite suite= new TestSuite(typeof(MathTest)); /// /// This constructor creates a suite with all the methods /// starting with "Test" that take no arguments. /// public class TestSuite: MarshalByRefObject, ITest { private ArrayList fTests= new ArrayList(10); private string fName; private bool fHasWarnings = false; /// Constructs an empty TestSuite. public TestSuite() { } /// Constructs a TestSuite from the given class. /// Adds all the methods /// starting with "Test" as test cases to the suite. /// Parts of this method was written at 2337 meters in the Hüffihütte, /// Kanton Uri public TestSuite(Type theClass) { fName= theClass.Name; ConstructorInfo constructor = GetConstructor(theClass); if (constructor == null) { AddTest(Warning("Class "+theClass.Name+" has no public constructor TestCase(String name)")); return; } if (theClass.IsNotPublic) { AddTest(Warning("Class "+theClass.Name+" is not public")); return; } Type superClass= theClass; ArrayList names= new ArrayList(); while (typeof(ITest).IsAssignableFrom(superClass)) { MethodInfo[] methods= superClass.GetMethods(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance); for (int i= 0; i < methods.Length; i++) { AddTestMethod(methods[i], names, constructor); } superClass= superClass.BaseType; } if (fTests.Count == 0) AddTest(Warning("No Tests found in "+theClass.ToString())); } /// /// /// /// /// public TestSuite(Type theClass, ref bool hasNonWarningTests) { hasNonWarningTests = false; fName= theClass.ToString(); ConstructorInfo constructor= GetConstructor(theClass); if (constructor == null) { return; } if (theClass.IsNotPublic) { return; } Type superClass= theClass; ArrayList names= new ArrayList(); while (typeof(ITest).IsAssignableFrom(superClass)) { MethodInfo[] methods= superClass.GetMethods(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance); for (int i= 0; i < methods.Length; i++) { AddTestMethod(methods[i], names, constructor); } superClass= superClass.BaseType; } if (fHasWarnings) { hasNonWarningTests = false; } else { hasNonWarningTests = (fTests.Count != 0); } } /// Constructs an empty TestSuite. public TestSuite(string name) { fName= name; } /// Adds a test to the suite. public void AddTest(ITest test) { fTests.Add(test); } private void AddTestMethod(MethodInfo m, ArrayList names, ConstructorInfo constructor) { string name= m.Name; if (names.Contains(name)) return; if (IsPublicTestMethod(m)) { names.Add(name); Object[] args= new Object[]{name}; try { AddTest((ITest)constructor.Invoke(args)); } catch (TypeLoadException e) { AddTest(Warning("Cannot instantiate test case: "+name + "( " + e.ToString() + ")")); } catch (TargetInvocationException e) { AddTest(Warning("Exception in constructor: "+name + "( " + e.ToString() + ")")); } catch (MemberAccessException e) { AddTest(Warning("Cannot access test case: "+name + "( " + e.ToString() + ")")); } } else { // almost a test method if (IsTestMethod(m)) AddTest(Warning("test method isn't public: "+m.Name)); } } /// Adds the tests from the given class to the suite public void AddTestSuite(Type testClass) { AddTest(new TestSuite(testClass)); } /// The number of test cases that will be run by this test. public int CountTestCases { get { int count= 0; foreach (ITest test in Tests) { count += test.CountTestCases; } return count; } } /// Gets a constructor which takes a single string as /// its argument. private ConstructorInfo GetConstructor(Type theClass) { Type[] args= { typeof(string) }; return theClass.GetConstructor(args); } /// /// Returns the name of the suite. Not all test suites have a name /// and this method can return null. /// public string Name { get { return fName; } } private bool IsPublicTestMethod(MethodInfo m) { return IsTestMethod(m) && m.IsPublic; } private bool IsTestMethod(MethodInfo m) { string name= m.Name; ParameterInfo[] parameters= m.GetParameters(); Type returnType= m.ReturnType; return parameters.Length == 0 && name.ToLower().StartsWith("test") && returnType.Equals(typeof(void)); } /// Runs the Tests and collects their result in a /// TestResult. public virtual void Run(TestResult result) { foreach (ITest test in Tests) { if (result.ShouldStop ) break; RunTest(test, result); } } /// /// /// /// /// public virtual void RunTest(ITest test, TestResult result) { test.Run(result); } /// The test at the given index. /// Formerly TestAt(int). public ITest this[int index] { get {return (ITest)fTests[index]; } } /// The number of Tests in this suite. public int TestCount { get {return fTests.Count; } } /// The Tests as an ArrayList. public ArrayList Tests { get { return fTests; } } /// /// /// /// public override string ToString() { if (Name != null) return Name; return base.ToString(); } private ITest Warning(string message) { fHasWarnings = true; return new WarningFail(message); } /// Returns a test which will fail and log a warning /// message. public class WarningFail: TestCase { private string fMessage; /// /// /// /// public WarningFail(string message): base("warning") { fMessage = message; } /// /// /// protected override void RunTest() { Fail(fMessage); } } } }