/// <summary> /// Analyses the test assembly and find all tests. The tests will be added to the UnitTestAssemblyResult /// </summary> /// <param name="testAssembly">Assembly that contains tests</param> /// <returns>UnitTestAssemblyResult as placeholder for each test</returns> private UnitTestAssemblyResult AnalyseTestAssembly(string testAssembly) { // load the assembly for reflection UnitTestAssemblyResult results = new UnitTestAssemblyResult(Path.GetFileNameWithoutExtension(testAssembly)); Assembly assembly = Assembly.ReflectionOnlyLoadFrom(testAssembly); // store the assembly version results.TestAssemblyVersion = assembly.GetName().Version; // and iterate through all public classes which have an parameterless constructor and // implements the ITestClass interface; get the list from the TestManager foreach (DictionaryEntry entry in TestManager.GetTestClassTypes(assembly)) { Type type = (Type)entry.Key; Type[] interfaces = (Type[])entry.Value; UnitTestClassResult classResult = new UnitTestClassResult(type.FullName); // iterate through all public parameterless instance methods that are declared in // this class and filter out the "...Initialize" and "...Cleanup" methods; get the list from the TestManager foreach (MethodInfo method in TestManager.GetTestMethods(type, interfaces)) { // add a new test result for the test method classResult.MethodResults.Add(new UnitTestResult(method.Name)); } // add the new class result; only if min one test found if (classResult.MethodResults.Count > 0) { results.ClassResults.Add(classResult); } } return(results); }
/// <summary> /// Parses the test results for a captured string. /// </summary> /// <param name="capturedOutput">A captured output that contains the debug messages that the test manager on the device has emitted.</param> /// <returns>The list of UnitTestAssemblyResult; one entry for each test assembly that was delivered to the constructor</returns> /*internal IList<UnitTestAssemblyResult> ParseCapturedOutput(string capturedOutput) * { * // parse the captured output line by line * foreach (string line in capturedOutput.Split(Environment.NewLine.ToArray())) * { * if (line == string.Empty) * { * continue; * } * OnDebugMessage(line); * } * return _results; * }*/ #endregion #region private methods /// <summary> /// Analyses the test assembly and find all tests. The tests will be added to the UnitTestAssemblyResult /// </summary> /// <param name="testAssembly">Assembly that contains tests</param> /// <returns>UnitTestAssemblyResult as placeholder for each test</returns> private UnitTestAssemblyResult AnalyseTestAssembly(string testAssembly) { // load the assembly for reflection var results = new UnitTestAssemblyResult(Path.GetFileNameWithoutExtension(testAssembly)); var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(testAssembly); //Assembly assembly = Assembly.ReflectionOnlyLoadFrom(testAssembly); //Assembly assembly = TypeLoader.Default.Load // store the assembly version results.TestAssemblyVersion = assembly.GetName().Version; // and iterate through all public classes which have an parameterless constructor and // implements the ITestClass interface; get the list from the TestManager ArrayList types = TestManager.GetTestClassTypes(assembly); if (types != null) { foreach (Type type in types) { var classResult = new UnitTestClassResult(type.FullName); // iterate through all public parameterless instance methods that are declared in // this class and filter out the "...Initialize" and "...Cleanup" methods; get the list from the TestManager ArrayList methods = TestManager.GetMethodsWithAttribute(type, typeof(TestMethodAttribute)); if (methods != null) { foreach (MethodInfo method in methods) { // add a new test result for the test method classResult.MethodResults.Add(new UnitTestResult(method.Name)); } } // add the new class result results.ClassResults.Add(classResult); } } return(results); }
/// <summary> /// Event handler gets called the a debug message from the device arrives the nanoFramework debugger /// </summary> /// <param name="message">The debug message</param> private void OnDebugMessage(string message) { string className = null; UnitTestResult result = null; Console.WriteLine(message); foreach (KeyValuePair <MessageParsing, string> entry in _regexParsing) { result = null; // test the message with all possible regex Match match = Regex.Match(message, entry.Value); if (match.Success) { // what have we found? switch (entry.Key) { // Tests started: => get the ticks per milliseconds case MessageParsing.Started: TicksPerMillisecond = decimal.Parse(match.Groups["ticksPerMillisecond"].ToString()); // activate the current results _currentResult = _results.Where(allResults => allResults.TestAssemblyName == match.Groups["assemblyName"].ToString()).Single(); _currentResult.TimeStamp = DateTime.Now.ToString("g"); break; // One test passed: Create the UnitTestResult case MessageParsing.Passed: className = match.Groups["fullClassName"].ToString(); result = new UnitTestResult(match.Groups["methodName"].ToString(), UnitTestStatus.Passed, decimal.Parse(match.Groups["elapsedTicks"].ToString()) / TicksPerMillisecond, null); break; // One test failed: Create the UnitTestResult case MessageParsing.Failed: className = match.Groups["fullClassName"].ToString(); result = new UnitTestResult(match.Groups["methodName"].ToString(), UnitTestStatus.Passed, 0, match.Groups["errorMessage"].ToString()); break; // All tests finished: one more assembly has finished the tests; done? case MessageParsing.Finished: _currentResult = null; _testedAssemblyCount++; // all assemblies tested? => detach the event handler and release the semaphore if (_testedAssemblyCount == _results.Count) { if (_debugEngine != null) { _debugEngine.OnDebugMessage -= OnDebugMessage; } _waitForFinished.Release(); } break; } break; } } // UnitTestResult created? if (result != null) { // find the class results UnitTestClassResult classResult = _currentResult.ClassResults.Where(entry => entry.TestClassName == className).FirstOrDefault(); // something went wrong if we don't find the test class in the results; maybe the pe-file doesn't match the corresponding dll/exe file if (classResult == null) { throw new ArgumentException($"TestClass {className} not found in the test results"); } // remove the placeholder result and add the current result classResult.MethodResults.RemoveAll(entry => entry.TestMethodName == result.TestMethodName); classResult.MethodResults.Add(result); // cumulate the execution time to the class and the assembly classResult.ExecutionDurationMilliseconds += result.ExecutionDurationMilliseconds; _currentResult.ExecutionDurationMilliseconds += result.ExecutionDurationMilliseconds; } }
/// <summary> /// Event handler gets called the a debug message from the device arrives the nanoFramework debugger /// </summary> /// <param name="message">The debug message</param> private void OnDebugMessage(object sender, SerialDataReceivedEventArgs e) { string className = null; UnitTestResult result = null; string received = _serialPort.ReadExisting(); _output.Append(received); Console.Write(received); if (!_output.ToString().Contains("Tests finished")) { return; } foreach (string message in _output.ToString().Split(Environment.NewLine.ToCharArray())) { foreach (KeyValuePair <MessageParsing, string> entry in _regexParsing) { result = null; // test the message with all possible regex Match match = Regex.Match(message, entry.Value); if (match.Success) { // what have we found? switch (entry.Key) { // Tests started: => get the ticks per milliseconds case MessageParsing.Started: TicksPerMillisecond = decimal.Parse(match.Groups["ticksPerMillisecond"].ToString()); // activate the current results _currentResult = _results.Where(allResults => allResults.TestAssemblyName == match.Groups["assemblyName"].ToString()).Single(); _currentResult.TimeStamp = DateTime.Now.ToString(new System.Globalization.CultureInfo("en-US")); break; // One test passed: Create the UnitTestResult case MessageParsing.Passed: className = match.Groups["fullClassName"].ToString(); result = new UnitTestResult(match.Groups["methodName"].ToString(), UnitTestStatus.Passed, decimal.Parse(match.Groups["elapsedTicks"].ToString()) / TicksPerMillisecond, null); break; // One test failed: Create the UnitTestResult case MessageParsing.Failed: className = match.Groups["fullClassName"].ToString(); result = new UnitTestResult(match.Groups["methodName"].ToString(), UnitTestStatus.Failed, 0, match.Groups["errorMessage"].ToString()); break; // All tests finished: one more assembly has finished the tests; done? case MessageParsing.Finished: _currentResult = null; _testedAssemblyCount++; // all assemblies tested? => detach the event handler and release the semaphore if (_testedAssemblyCount == _results.Count) { if (_serialPort != null) { _serialPort.DataReceived -= OnDebugMessage; _serialPort.Close(); } _waitForFinished.Release(); } break; } break; } } // UnitTestResult created? if (result != null) { // find the class results UnitTestClassResult classResult = _currentResult.ClassResults.Where(entry => entry.TestClassName == className).FirstOrDefault(); // something went wrong if we don't find the test class in the results; maybe the pe-file doesn't match the corresponding dll/exe file if (classResult == null) { throw new ArgumentException($"TestClass {className} not found in the test results"); } // remove the placeholder result and add the current result classResult.MethodResults.RemoveAll(entry => entry.TestMethodName == result.TestMethodName); classResult.MethodResults.Add(result); if (result.TestStatus == UnitTestStatus.Failed) { classResult.ClassStatus = UnitTestStatus.Failed; _currentResult.AssemblyStatus = UnitTestStatus.Failed; } // cumulate the execution time to the class and the assembly classResult.ExecutionDurationMilliseconds += result.ExecutionDurationMilliseconds; _currentResult.ExecutionDurationMilliseconds += result.ExecutionDurationMilliseconds; } } }