public void StartGroup (TestGroup testGroup)
 {
     BeginInvokeOnMainThread (() => {
         this.testsSection = new Section (testGroup.Name);
         Root.Add (this.testsSection);
     });
 }
        /// <summary>
        /// Reflect, read and prepare the tags for the group metadata. Performs 
        /// the work if this is the first time the metadata has been seen.
        /// </summary>
        /// <param name="group">The test group.</param>
        private void CreateClassTags(TestGroup group)
        {
            // 1. Full class name
            //_groupTags.AddTag(group.FullName);

            // 2. Class name
            _groupTags.AddTag(group.Name);

            // 3. All [Tag] attributes on the type
            foreach (string tag in group.Tags)
            {
                _groupTags.AddTag(tag);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Reflect, read and prepare the tags for the group metadata. Performs
        /// the work if this is the first time the metadata has been seen.
        /// </summary>
        /// <param name="group">The test group.</param>
        private void CreateClassTags(TestGroup group)
        {
            // 1. Full class name
            //_groupTags.AddTag(group.FullName);

            // 2. Class name
            _groupTags.AddTag(group.Name);

            // 3. All [Tag] attributes on the type
            foreach (string tag in group.Tags)
            {
                _groupTags.AddTag(tag);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Initializes a new instance of the TagManager class.
        /// </summary>
        /// <param name="group">The test group eing filter.</param>
        /// <param name="methods">The set of methods to run.</param>
        public TagManager(TestGroup group)
        {
            _group         = group;
            _groupTags     = new Tags();
            _methodTags    = new Dictionary <TestMethod, Tags>();
            _tagsToMethods = new Dictionary <string, List <TestMethod> >();
            Universe       = new List <TestMethod>(group.Methods);

            CreateClassTags(_group);
            foreach (TestMethod method in group.Methods)
            {
                CreateMethodTags(method);
            }
        }
        /// <summary>
        /// Initializes a new instance of the TagManager class.
        /// </summary>
        /// <param name="group">The test group eing filter.</param>
        /// <param name="methods">The set of methods to run.</param>
        public TagManager(TestGroup group)
        {
            _group = group;
            _groupTags = new Tags();
            _methodTags = new Dictionary<TestMethod, Tags>();
            _tagsToMethods = new Dictionary<string, List<TestMethod>>();
            Universe = new List<TestMethod>(group.Methods);

            CreateClassTags(_group);
            foreach (TestMethod method in group.Methods)
            {
                CreateMethodTags(method);
            }
        }
Ejemplo n.º 6
0
        private static TestGroup CreateGroup(Type type)
        {
            TestGroup group = new TestGroup();

            group.Name = type.Name;
            group.Tags.Add(type.Name);
            group.Tags.Add(type.FullName);
            if (type.GetCustomAttributes(true).Where(a => a.GetType() == typeof(FunctionalTestAttribute)).Any())
            {
                group.Tags.Add("Functional");
            }
            foreach (TagAttribute attr in type.GetCustomAttributes(true).Where(a => a.GetType() == typeof(TagAttribute)))
            {
                group.Tags.Add(attr.Tag);
            }
            return(group);
        }
Ejemplo n.º 7
0
        private static TestGroup CreateGroup(Type type)
        {
            TestGroup group = new TestGroup();

            group.Name = type.Name;
            group.Tags.Add(type.Name);
            group.Tags.Add(type.FullName);

            if (type.GetTypeInfo().GetCustomAttributes <FunctionalTestAttribute>().Any())
            {
                group.Tags.Add("Functional");
            }

            foreach (TagAttribute attr in type.GetTypeInfo().GetCustomAttributes <TagAttribute>())
            {
                group.Tags.Add(attr.Tag);
            }
            return(group);
        }
Ejemplo n.º 8
0
        private static void LoadTestAssembly(TestHarness harness, Assembly testAssembly)
        {
            Dictionary <Type, TestGroup>   groups    = new Dictionary <Type, TestGroup>();
            Dictionary <TestGroup, object> instances = new Dictionary <TestGroup, object>();

            foreach (Type type in testAssembly.GetTypes())
            {
                foreach (MethodInfo method in type.GetMethods())
                {
                    if (method.GetCustomAttributes(true).Where(a => a.GetType() == typeof(TestMethodAttribute) ||
                                                               a.GetType() == typeof(AsyncTestMethodAttribute))
                        .Any())
                    {
                        TestGroup group    = null;
                        object    instance = null;
                        if (!groups.TryGetValue(type, out group))
                        {
                            group = CreateGroup(type);
                            harness.Groups.Add(group);
                            groups[type] = group;

                            instance = Activator.CreateInstance(type);
                            TestBase testBase = instance as TestBase;
                            if (testBase != null)
                            {
                                testBase.SetTestHarness(harness);
                            }

                            instances[group] = instance;
                        }
                        else
                        {
                            instances.TryGetValue(group, out instance);
                        }

                        TestMethod test = CreateMethod(type, instance, method);
                        group.Methods.Add(test);
                    }
                }
            }
        }
 void ITestReporter.StartGroup (TestGroup group)
 {
     this.currentGroup = new GroupDescription (group);
     this.groups.Add (this.currentGroup);
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Run the unit tests.
        /// </summary>
        public async void RunAsync()
        {
            // Ensure there's an interface to display the test results.
            if (this.Reporter == null)
            {
                throw new ArgumentNullException("Reporter");
            }

            // Setup the progress/failure counters
            this.Progress = 0;
            this.Failures = 0;

            // Filter out any test methods based on the current settings
            int filteredTestCount = FilterTests();

            // Write out the test status message which may be modified by the
            // filters
            Reporter.Status(this.Settings.TestRunStatusMessage);

            // Enumerators that track the current group and method to execute
            // (which allows reentrancy into the test loop below to resume at
            // the correct location).
            IEnumerator <TestGroup>  groups  = this.Groups.OrderBy(g => g.Name).GetEnumerator();
            IEnumerator <TestMethod> methods = null;

            // Keep a reference to the current group so we can pass it to the
            // Reporter's EndGroup (we don't need one for the test method,
            // however, because we close over in the continuation).
            TestGroup currentGroup = null;

            // Setup the UI
            this.Reporter.StartRun(this);

            // The primary test loop is a "recursive" closure that will pass
            // itself as the continuation to async tests.
            //
            // Note: It's really important for performance to note that any
            // calls to testLoop only occur in the tail position.
            DateTime    RunStartTime = DateTime.UtcNow;
            Func <Task> testLoop     = null;

            testLoop =
                async() =>
            {
                if (methods != null && methods.MoveNext())
                {
                    // If we were in the middle of a test group and there
                    // are more methods to execute, let's move to the next
                    // test method.

                    // Update the progress
                    this.Progress++;
                    Reporter.Progress(this);
                    // Start the test method
                    Reporter.StartTest(methods.Current);
                    if (methods.Current.Excluded)
                    {
                        // Ignore excluded tests and immediately recurse.
                        Reporter.EndTest(methods.Current);
                        await testLoop();
                    }
                    else
                    {
                        // Get the start time for individual tests
                        DateTime testStartTime = DateTime.UtcNow;

                        // Record the test result, upload the test log as a blob and clear the
                        // log for next test
                        Func <Task> recordTestResult = async() =>
                        {
                            if (!Settings.ManualMode)
                            {
                                // upload test log to sunlight blob container
                                string relativeFilePath = this.Platform + "/" + Guid.NewGuid().ToString() + ".txt";

                                string blobStorageSasUrl = GetBlobStorageSasUrl(this.Settings.Custom["TestFrameworkStorageContainerUrl"],
                                                                                this.Settings.Custom["TestFrameworkStorageContainerSasToken"],
                                                                                relativeFilePath);

                                await UploadToBlobContainerAsync(blobStorageSasUrl, LogDump.ToString());

                                // record the test result
                                var testResult = new TestResult()
                                {
                                    FullName     = methods.Current.Name,
                                    StartTime    = testStartTime,
                                    EndTime      = DateTime.UtcNow,
                                    Outcome      = methods.Current.Passed ? "Passed" : "Failed",
                                    Source       = currentGroup.Name,
                                    ReferenceUrl = relativeFilePath
                                };

                                // Add the test result to the test result collection
                                testRun.AddTestResult(testResult);
                                LogDump.Clear();
                            }
                        };
                        // Execute the test method
                        methods.Current.Test.Start(
                            new ActionContinuation
                        {
                            OnSuccess = async() =>
                            {
                                // Mark the test as passing, update the
                                // UI, and continue with the next test.
                                methods.Current.Passed = true;
                                methods.Current.Test   = null;
                                Reporter.EndTest(methods.Current);
                                await recordTestResult();
                                await testLoop();
                            },
                            OnError = async(message) =>
                            {
                                // Mark the test as failing, update the
                                // UI, and continue with the next test.
                                methods.Current.Passed    = false;
                                methods.Current.Test      = null;
                                methods.Current.ErrorInfo = message;
                                this.Failures++;
                                System.Diagnostics.Debug.WriteLine(message);
                                Reporter.Error(message);
                                LogDump.AppendLine(message);
                                Reporter.EndTest(methods.Current);
                                await recordTestResult();
                                await testLoop();
                            }
                        });
                    }
                }
                else if (groups.MoveNext())
                {
                    // If we've finished a test group and there are more,
                    // then move to the next one.

                    // Finish the UI for the last group.
                    if (currentGroup != null)
                    {
                        Reporter.EndGroup(currentGroup);
                        currentGroup = null;
                    }

                    // Setup the UI for this next group
                    currentGroup = groups.Current;
                    Reporter.StartGroup(currentGroup);

                    // Get the methods and immediately recurse which will
                    // start executing them.
                    methods = groups.Current.Methods.OrderBy(m => m.Name).GetEnumerator();
                    await testLoop();
                }
                else
                {
                    if (!Settings.ManualMode)
                    {
                        // upload test suite result to sunlight blob container
                        string blobStorageSasUrl = GetBlobStorageSasUrl(this.Settings.Custom["TestFrameworkStorageContainerUrl"],
                                                                        this.Settings.Custom["TestFrameworkStorageContainerSasToken"],
                                                                        this.Platform + "-detail.json");
                        string fileContent = JsonConvert.SerializeObject(testRun.TestResults.ToList(), Formatting.Indented);
                        await UploadToBlobContainerAsync(blobStorageSasUrl, fileContent);

                        // upload test result summary to blob container
                        var masterResult = new MasterTestResult()
                        {
                            FullName     = this.Platform + "-" + Settings.Custom["RuntimeVersion"],
                            Outcome      = Failures > 0 ? "Failed" : "Passed",
                            TotalCount   = testRun.TestCount,
                            Passed       = filteredTestCount - Failures,
                            Failed       = Failures,
                            Skipped      = testRun.TestCount - filteredTestCount,
                            StartTime    = RunStartTime,
                            EndTime      = DateTime.UtcNow,
                            ReferenceUrl = this.Platform + "-detail.json"
                        };

                        // upload test suite result to sunlight blob container
                        blobStorageSasUrl = GetBlobStorageSasUrl(this.Settings.Custom["TestFrameworkStorageContainerUrl"],
                                                                 this.Settings.Custom["TestFrameworkStorageContainerSasToken"],
                                                                 this.Platform + "-master.json");
                        fileContent = JsonConvert.SerializeObject(masterResult, Formatting.Indented);
                        await UploadToBlobContainerAsync(blobStorageSasUrl, fileContent);
                    }
                    // Otherwise if we've finished the entire test run

                    // Finish the UI for the last group and update the
                    // progress after the very last test method.
                    Reporter.EndGroup(currentGroup);
                    Reporter.Progress(this);

                    // Finish the UI for the test run.
                    Reporter.EndRun(this);
                }
            };

            // Start running the tests
            await testLoop();
        }
        private static TestGroup CreateGroup(Type type)
        {
            TestGroup group = new TestGroup();
            group.Name = type.Name;
            group.Tags.Add(type.Name);
            group.Tags.Add(type.FullName);

            if (type.GetTypeInfo().GetCustomAttributes<FunctionalTestAttribute>().Any())
            {
                group.Tags.Add("Functional");
            }

            foreach (TagAttribute attr in type.GetTypeInfo().GetCustomAttributes<TagAttribute>())
            {
                group.Tags.Add(attr.Tag);
            }
            return group;
        }
 public async void EndGroup(TestGroup group)
 {
     await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
     {
         _currentGroup = null;
     });
 }
 public async void StartGroup(TestGroup group)
 {
     await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
     {
         _currentGroup = new GroupDescription { Name = group.Name };
         _groups.Add(_currentGroup);
     });
 }
 public GroupDescription (TestGroup group)
 {
     Group = group;
     this.tests.CollectionChanged += (sender, e) => HasFailures = this.tests.Any (t => !t.Test.Passed);
 }
Ejemplo n.º 15
0
 private static TestGroup CreateGroup(TypeInfo type)
 {
     TestGroup group = new TestGroup();
     group.Name = type.Name;
     group.Tags.Add(type.Name);
     group.Tags.Add(type.FullName);
     if (type.GetCustomAttributes(true).Where(a => a.GetType() == typeof(FunctionalTestAttribute)).Any())
     {
         group.Tags.Add("Functional");
     }
     foreach (TagAttribute attr in type.GetCustomAttributes(true).Where(a => a.GetType() == typeof(TagAttribute)))
     {
         group.Tags.Add(attr.Tag);
     }
     return group;
 }
 public void StartGroup(TestGroup group)
 {
     Dispatcher.BeginInvoke(() =>
     {
         _currentGroup = new GroupDescription { Name = group.Name };
         _groups.Add(_currentGroup);
     });
 }
        /// <summary>
        /// Run the unit tests.
        /// </summary>
        public async void RunAsync()
        {
            // Ensure there's an interface to display the test results.
            if (this.Reporter == null)
            {
                throw new ArgumentNullException("Reporter");
            }

            /// Record the test metadata to the test run object at the start of the test run
            FillTestRunMetaData();

            // Setup the progress/failure counters
            this.Progress = 0;
            this.Failures = 0;

            // Filter out any test methods based on the current settings
            int filteredTestCount = FilterTests();

            // get the actual count of tests going to run
            testRun.TestCount = filteredTestCount;

            // Write out the test status message which may be modified by the
            // filters
            Reporter.Status(this.Settings.TestRunStatusMessage);

            // Enumerators that track the current group and method to execute
            // (which allows reentrancy into the test loop below to resume at
            // the correct location).
            IEnumerator <TestGroup>  groups  = this.Groups.OrderBy(g => g.Name).GetEnumerator();
            IEnumerator <TestMethod> methods = null;

            // Keep a reference to the current group so we can pass it to the
            // Reporter's EndGroup (we don't need one for the test method,
            // however, because we close over in the continuation).
            TestGroup currentGroup = null;

            // Create daylight test run and get the run id
            string runId = String.Empty;

            if (!Settings.ManualMode)
            {
                runId = await TestLogger.CreateDaylightRun(testRun, Settings);
            }

            // Setup the UI
            this.Reporter.StartRun(this);

            // The primary test loop is a "recursive" closure that will pass
            // itself as the continuation to async tests.
            //
            // Note: It's really important for performance to note that any
            // calls to testLoop only occur in the tail position.
            JObject     sasResponseObject = null;
            DateTime    RunStartTime      = DateTime.UtcNow;
            Func <Task> testLoop          = null;

            // Get the SAS token to upload the test logs to upload test logs to blob store
            if (!Settings.ManualMode && !String.IsNullOrEmpty(runId))
            {
                sasResponseObject = await TestLogger.GetSaSToken(Settings);
            }
            testLoop =
                async() =>
            {
                if (methods != null && methods.MoveNext())
                {
                    // If we were in the middle of a test group and there
                    // are more methods to execute, let's move to the next
                    // test method.

                    // Update the progress
                    this.Progress++;
                    Reporter.Progress(this);
                    // Start the test method
                    Reporter.StartTest(methods.Current);
                    if (methods.Current.Excluded)
                    {
                        // Ignore excluded tests and immediately recurse.
                        Reporter.EndTest(methods.Current);
                        await testLoop();
                    }
                    else
                    {
                        // Get the start time for individual tests
                        DateTime testStartTime = DateTime.UtcNow;

                        // Record the test result, upload the test log as a blob and clear the
                        // log for next test
                        Func <Task> recordTestResult = async() =>
                        {
                            if (!Settings.ManualMode && !String.IsNullOrEmpty(runId))
                            {
                                var log = new TestLogs()
                                {
                                    LogLines = LogDump.ToString(),
                                    LogHash  = Guid.NewGuid().ToString()
                                };
                                // record the test result
                                var testResult = new TestResult()
                                {
                                    FullName  = methods.Current.Name,
                                    StartTime = testStartTime,
                                    EndTime   = DateTime.UtcNow,
                                    Outcome   = methods.Current.Passed ? "Passed" : "Failed",
                                    RunId     = runId,
                                    Tags      = new List <string> {
                                        Platform
                                    },
                                    Source = currentGroup.Name,
                                    Logs   = sasResponseObject != null ? log : null
                                };

                                // upload test log to the blob store
                                if (sasResponseObject != null)
                                {
                                    await TestLogger.UploadTestLog(log, sasResponseObject);
                                }

                                // Add the test result to the test result collection, which will eventually
                                // be uploaded to daylight
                                testRun.AddTestResult(testResult);
                                LogDump.Clear();
                            }
                        };
                        // Execute the test method
                        methods.Current.Test.Start(
                            new ActionContinuation
                        {
                            OnSuccess = async() =>
                            {
                                // Mark the test as passing, update the
                                // UI, and continue with the next test.
                                methods.Current.Passed = true;
                                methods.Current.Test   = null;
                                Reporter.EndTest(methods.Current);
                                await recordTestResult();
                                await testLoop();
                            },
                            OnError = async(message) =>
                            {
                                // Mark the test as failing, update the
                                // UI, and continue with the next test.
                                methods.Current.Passed    = false;
                                methods.Current.Test      = null;
                                methods.Current.ErrorInfo = message;
                                this.Failures++;
                                System.Diagnostics.Debug.WriteLine(message);
                                Reporter.Error(message);
                                LogDump.AppendLine(message);
                                Reporter.EndTest(methods.Current);
                                await recordTestResult();
                                await testLoop();
                            }
                        });
                    }
                }
                else if (groups.MoveNext())
                {
                    // If we've finished a test group and there are more,
                    // then move to the next one.

                    // Finish the UI for the last group.
                    if (currentGroup != null)
                    {
                        Reporter.EndGroup(currentGroup);
                        currentGroup = null;
                    }

                    // Setup the UI for this next group
                    currentGroup = groups.Current;
                    Reporter.StartGroup(currentGroup);

                    // Get the methods and immediately recurse which will
                    // start executing them.
                    methods = groups.Current.Methods.OrderBy(m => m.Name).GetEnumerator();
                    await testLoop();
                }
                else
                {
                    if (!Settings.ManualMode && !String.IsNullOrEmpty(runId))
                    {
                        // post all the test results to daylight
                        await TestLogger.PostTestResults(testRun.TestResults.ToList(), Settings);

                        // String to store the test result summary of the entire suite
                        StringBuilder resultLog = new StringBuilder("Total Tests:" + filteredTestCount);
                        resultLog.AppendLine();
                        resultLog.AppendLine("Passed Tests:" + (filteredTestCount - Failures).ToString());
                        resultLog.AppendLine("Failed Tests:" + Failures);
                        resultLog.AppendLine("Detailed Results:" + Settings.Custom["DayLightUrl"] + "/" + Settings.Custom["DaylightProject"] + "/runs/" + runId);

                        var logs = new TestLogs()
                        {
                            LogLines = resultLog.ToString(),
                            LogHash  = Guid.NewGuid().ToString()
                        };
                        // Record the the result of the entire test suite to master test run
                        var testResult = new TestResult()
                        {
                            FullName  = Platform + " " + Settings.Custom["RuntimeVersion"],
                            Name      = Platform + " " + Settings.Custom["RuntimeVersion"],
                            StartTime = RunStartTime,
                            EndTime   = DateTime.UtcNow,
                            Outcome   = Failures > 0 ? "Failed" : "Passed",
                            RunId     = Settings.Custom["MasterRunId"],
                            Tags      = new List <string> {
                                Platform
                            },
                            Source = "Managed",
                            Logs   = sasResponseObject != null ? logs : null
                        };

                        // Upload the log of the test result summary for the test suite
                        if (sasResponseObject != null)
                        {
                            await TestLogger.UploadTestLog(logs, sasResponseObject);
                        }

                        // Post the test suite result to master run
                        await TestLogger.PostTestResults(new List <TestResult> {
                            testResult
                        }, Settings);
                    }
                    // Otherwise if we've finished the entire test run

                    // Finish the UI for the last group and update the
                    // progress after the very last test method.
                    Reporter.EndGroup(currentGroup);
                    Reporter.Progress(this);

                    // Finish the UI for the test run.
                    Reporter.EndRun(this);
                }
            };

            // Start running the tests
            await testLoop();
        }
 public async void EndGroup(TestGroup group)
 {
     await Dispatcher.InvokeAsync(() =>
     {
         currentGroup = null;
     });
 }
 public async void StartGroup(TestGroup group)
 {
     await Dispatcher.InvokeAsync(() =>
     {
         currentGroup = new GroupDescription { Name = group.Name };
         groups.Add(currentGroup);
     });
 }
        public void EndGroup (TestGroup testGroup)
        {
			
        }
 void ITestReporter.EndGroup (TestGroup group)
 {
 }
 public void EndGroup(TestGroup group)
 {
     Dispatcher.BeginInvoke(() =>
     {
         _currentGroup = null;
     });
 }
Ejemplo n.º 23
0
        /// <summary>
        /// Run the unit tests.
        /// </summary>
        public void RunAsync()
        {
            // Ensure there's an interface to display the test results.
            if (this.Reporter == null)
            {
                throw new ArgumentNullException("Reporter");
            }

            // Setup the progress/failure counters
            this.Progress = 0;
            this.Failures = 0;

            // Filter out any test methods based on the current settings
            FilterTests();

            // Write out the test status message which may be modified by the
            // filters
            Reporter.Status(this.Settings.TestRunStatusMessage);

            // Enumerators that track the current group and method to execute
            // (which allows reentrancy into the test loop below to resume at
            // the correct location).
            IEnumerator <TestGroup>  groups  = this.Groups.OrderBy(g => g.Name).GetEnumerator();
            IEnumerator <TestMethod> methods = null;

            // Keep a reference to the current group so we can pass it to the
            // Reporter's EndGroup (we don't need one for the test method,
            // however, because we close over in the continuation).
            TestGroup currentGroup = null;

            // Setup the UI
            this.Reporter.StartRun(this);

            // The primary test loop is a "recursive" closure that will pass
            // itself as the continuation to async tests.
            //
            // Note: It's really important for performance to note that any
            // calls to testLoop only occur in the tail position.
            Action testLoop = null;

            testLoop =
                () =>
            {
                if (methods != null && methods.MoveNext())
                {
                    // If we were in the middle of a test group and there
                    // are more methods to execute, let's move to the next
                    // test method.

                    // Update the progress
                    this.Progress++;
                    Reporter.Progress(this);

                    // Start the test method
                    Reporter.StartTest(methods.Current);
                    if (methods.Current.Excluded)
                    {
                        // Ignore excluded tests and immediately recurse.
                        Reporter.EndTest(methods.Current);
                        testLoop();
                    }
                    else
                    {
                        // Execute the test method
                        methods.Current.Test.Start(
                            new ActionContinuation
                        {
                            OnSuccess = () =>
                            {
                                // Mark the test as passing, update the
                                // UI, and continue with the next test.
                                methods.Current.Passed = true;
                                methods.Current.Test   = null;
                                Reporter.EndTest(methods.Current);
                                testLoop();
                            },
                            OnError = (message) =>
                            {
                                // Mark the test as failing, update the
                                // UI, and continue with the next test.
                                methods.Current.Passed    = false;
                                methods.Current.Test      = null;
                                methods.Current.ErrorInfo = message;
                                this.Failures++;
                                Reporter.Error(message);
                                Reporter.EndTest(methods.Current);
                                testLoop();
                            }
                        });
                    }
                }
                else if (groups.MoveNext())
                {
                    // If we've finished a test group and there are more,
                    // then move to the next one.

                    // Finish the UI for the last group.
                    if (currentGroup != null)
                    {
                        Reporter.EndGroup(currentGroup);
                        currentGroup = null;
                    }

                    // Setup the UI for this next group
                    currentGroup = groups.Current;
                    Reporter.StartGroup(currentGroup);

                    // Get the methods and immediately recurse which will
                    // start executing them.
                    methods = groups.Current.Methods.OrderBy(m => m.Name).GetEnumerator();
                    testLoop();
                }
                else
                {
                    // Otherwise if we've finished the entire test run

                    // Finish the UI for the last group and update the
                    // progress after the very last test method.
                    Reporter.EndGroup(currentGroup);
                    Reporter.Progress(this);

                    // Finish the UI for the test run.
                    Reporter.EndRun(this);
                }
            };

            // Start running the tests
            testLoop();
        }