PageRenderTime 27ms CodeModel.GetById 43ms RepoModel.GetById 1ms app.codeStats 0ms

/Silverlight4/Infrastructure/TestFramework/UnitTesting/TestMethodManager.cs

https://github.com/kvervo/HorizontalLoopingSelector
C# | 318 lines | 174 code | 43 blank | 101 comment | 38 complexity | 4bde5605d36a1bb8620a6df3c89d19eb MD5 | raw file
  1. // (c) Copyright Microsoft Corporation.
  2. // This source is subject to the Microsoft Public License (Ms-PL).
  3. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  4. // All other rights reserved.
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Reflection;
  8. using Microsoft.Silverlight.Testing.Harness;
  9. using Microsoft.Silverlight.Testing.UnitTesting.Metadata;
  10. namespace Microsoft.Silverlight.Testing.Harness
  11. {
  12. /// <summary>
  13. /// Manager for planning, processing, and reporting the result of a single
  14. /// test method for a unit test provider.
  15. /// </summary>
  16. public partial class TestMethodManager : UnitTestCompositeWorkItem
  17. {
  18. /// <summary>
  19. /// Underlying test class object.
  20. /// </summary>
  21. private ITestClass _testClass;
  22. /// <summary>
  23. /// Underlying test method object.
  24. /// </summary>
  25. private ITestMethod _testMethod;
  26. /// <summary>
  27. /// Reference to an instance of the test class.
  28. /// </summary>
  29. private object _instance;
  30. /// <summary>
  31. /// Scenario result of the test method.
  32. /// </summary>
  33. private ScenarioResult _result;
  34. /// <summary>
  35. /// The started time of execution.
  36. /// </summary>
  37. private DateTime _started;
  38. /// <summary>
  39. /// Stores a collection of written lines.
  40. /// </summary>
  41. private List<string> _output;
  42. /// <summary>
  43. /// Gets or sets a value indicating whether the bug attribute's logic
  44. /// has already been processed.
  45. /// </summary>
  46. private bool BugAttributeProcessed { get; set; }
  47. /// <summary>
  48. /// A value indicating whether the bug attribute was present on this
  49. /// method. If it is, the result will be inverted at completion.
  50. /// </summary>
  51. private bool _bugAttributePresent;
  52. /// <summary>
  53. /// Contains the main test contents.
  54. /// </summary>
  55. private UnitTestMethodContainer _mainTestMethodContainer;
  56. /// <summary>
  57. /// Constructor for a test method manager, which handles executing a single test method
  58. /// for a unit test provider.
  59. /// </summary>
  60. /// <param name="testHarness">The unit test harness object.</param>
  61. /// <param name="testClass">The test class metadata object.</param>
  62. /// <param name="testMethod">The test method metadata object.</param>
  63. /// <param name="instance">The test class instance.</param>
  64. /// <param name="provider">The unit test provider.</param>
  65. public TestMethodManager(UnitTestHarness testHarness, ITestClass testClass, ITestMethod testMethod, object instance, IUnitTestProvider provider) : base(testHarness, provider)
  66. {
  67. _testClass = testClass;
  68. _testMethod = testMethod;
  69. _instance = instance;
  70. }
  71. /// <summary>
  72. /// Log a start message.
  73. /// </summary>
  74. private void LogStartMessage()
  75. {
  76. LogWriter.TestMethodStage(_testMethod, TestStage.Starting);
  77. TestHarness.Events.SendTestMethodStarting(new TestMethodStartingEventArgs(_testMethod, _testClass, TestHarness));
  78. }
  79. /// <summary>
  80. /// Log an end message.
  81. /// </summary>
  82. private void LogEndMessage()
  83. {
  84. LogWriter.TestMethodStage(_testMethod, TestStage.Finishing);
  85. }
  86. /// <summary>
  87. /// Gets the write line output list.
  88. /// </summary>
  89. public List<string> WriteLineOutput
  90. {
  91. get { return _output; }
  92. }
  93. /// <summary>
  94. /// Handles the write line event for the test method.
  95. /// </summary>
  96. /// <param name="e">The string event arguments.</param>
  97. protected virtual void OnWriteLine(StringEventArgs e)
  98. {
  99. if (_output == null)
  100. {
  101. _output = new List<string> { e.Value };
  102. }
  103. else
  104. {
  105. _output.Add(e.Value);
  106. }
  107. LogWriter.DebugWriteLine(e.Value);
  108. }
  109. /// <summary>
  110. /// First invoke, plan for the method's execution.
  111. /// </summary>
  112. protected override void FirstInvoke()
  113. {
  114. // [Ignore]
  115. if (Provider.HasCapability(UnitTestProviderCapabilities.MethodCanIgnore) && _testMethod.Ignore)
  116. {
  117. LogWriter.Ignore(TestGranularity.TestScenario, _testMethod.Name);
  118. return;
  119. }
  120. _testMethod.DecorateInstance(_instance);
  121. _testMethod.WriteLine += (object sender, StringEventArgs e) => OnWriteLine(e);
  122. // Log Start
  123. LogStartMessage();
  124. // [Bug] attributes that are not fixed modify test method logic
  125. ICollection<Attribute> bugs = ReflectionUtility.GetAttributes(_testMethod, typeof(BugAttribute), false);
  126. if (bugs != null && bugs.Count > 0)
  127. {
  128. foreach (Attribute attribute in bugs)
  129. {
  130. BugAttribute bug = attribute as BugAttribute;
  131. if (!bug.Fixed)
  132. {
  133. _bugAttributePresent = true;
  134. LogWriter.KnownIssue(bug.Description);
  135. }
  136. }
  137. }
  138. // [TestInitialize]
  139. if (_testClass.TestInitializeMethod != null)
  140. {
  141. EnqueueMethodDispatcher(_testClass.TestInitializeMethod);
  142. }
  143. // Track the approximate starting time - actual start time is >= 1 dispatcher interval
  144. EnqueueQuick(() => _started = DateTime.Now);
  145. // [TestMethod] - actual test scenario
  146. _mainTestMethodContainer = new UnitTestMethodContainer(TestHarness, _instance, _testMethod.Method, _testMethod, TestGranularity.TestScenario);
  147. _mainTestMethodContainer.UnhandledException += new EventHandler<UnhandledExceptionEventArgs>(UnhandledMethodException);
  148. _mainTestMethodContainer.Complete += new EventHandler(CompleteMethod);
  149. Enqueue(_mainTestMethodContainer);
  150. // [TestCleanup]
  151. if (_testClass.TestCleanupMethod != null)
  152. {
  153. EnqueueMethodDispatcher(_testClass.TestCleanupMethod);
  154. }
  155. // Log End
  156. EnqueueQuick(LogEndMessage);
  157. }
  158. /// <summary>
  159. /// Sets the start and finish times on the ScenarioResult object.
  160. /// </summary>
  161. private void SetResultTimes()
  162. {
  163. _result.Started = _started;
  164. _result.Finished = DateTime.Now;
  165. }
  166. /// <summary>
  167. /// Creates the ScenarioResult instance for this test method.
  168. /// </summary>
  169. /// <param name="outcome">The initial test outcome value.</param>
  170. private void CreateNewResult(TestOutcome outcome)
  171. {
  172. _result = new ScenarioResult(_testMethod, _testClass, outcome, null);
  173. SetResultTimes();
  174. }
  175. /// <summary>
  176. /// Process the result.
  177. /// </summary>
  178. /// <param name="sender">Source object.</param>
  179. /// <param name="e">Event arguments.</param>
  180. private void CompleteMethod(object sender, EventArgs e)
  181. {
  182. if (_testMethod.ExpectedException != null && _result == null)
  183. {
  184. CreateNewResult(TestOutcome.Failed);
  185. // Don't log this when the bug attribute is present
  186. if (_bugAttributePresent == false)
  187. {
  188. LogWriter.NoExceptionWhenExpected(_testMethod.ExpectedException.ExceptionType, _testClass, _testMethod);
  189. }
  190. }
  191. if (_result == null)
  192. {
  193. CreateNewResult(TestOutcome.Passed);
  194. }
  195. // Invert the result when the bug attribute is present
  196. if (_bugAttributePresent && !BugAttributeProcessed)
  197. {
  198. BugAttributeProcessed = true;
  199. bool bugVerified = _result.Result == TestOutcome.Failed;
  200. TestOutcome newOutcome = bugVerified ? TestOutcome.Passed : TestOutcome.Failed;
  201. _result.Result = newOutcome;
  202. // Log a warning when the bug cannot be verified
  203. if (!bugVerified)
  204. {
  205. LogWriter.Warning(Properties.UnitTestMessage.TestMethodManager_CompleteMethod_UnVerifiedBug);
  206. }
  207. }
  208. LogWriter.TestResult(_result);
  209. // Store the result
  210. TestHarness.TrackScenarioResult(_result);
  211. // Overlaps, could consider fixing in a future release
  212. TestHarness.Events.SendTestMethodCompleted(new TestMethodCompletedEventArgs(_result));
  213. }
  214. /// <summary>
  215. /// Process an unhandled exception for the method.
  216. /// </summary>
  217. /// <param name="sender">Source object.</param>
  218. /// <param name="e">Unhandled exception event arguments.</param>
  219. private void UnhandledMethodException(object sender, UnhandledExceptionEventArgs e)
  220. {
  221. TestOutcome res;
  222. Exception excp = (Exception)e.ExceptionObject;
  223. IExpectedException expected = _testMethod.ExpectedException;
  224. Type expectedType = expected != null ? expected.ExceptionType : null;
  225. if (excp == null)
  226. {
  227. throw new InvalidOperationException();
  228. }
  229. // Unwrap the Exception
  230. if (excp.GetType() == typeof(TargetInvocationException) && excp.InnerException != null)
  231. {
  232. excp = excp.InnerException;
  233. }
  234. res = excp is TimeoutException ? TestOutcome.Timeout : excp.Message.Contains("Inconclusive") ? TestOutcome.Inconclusive : TestOutcome.Failed;
  235. if (expected != null)
  236. {
  237. // Was it expected?
  238. Type excpType = excp.GetType();
  239. if (excpType == expectedType || excpType.IsSubclassOf(expectedType))
  240. {
  241. res = TestOutcome.Passed;
  242. }
  243. else
  244. {
  245. LogWriter.IncorrectException(_testMethod.ExpectedException.ExceptionType, excpType, _testClass, _testMethod);
  246. LogWriter.LogException(excp, _testClass, _testMethod);
  247. }
  248. }
  249. else
  250. {
  251. // Regular Exception type
  252. LogWriter.LogException(excp, _testClass, _testMethod);
  253. }
  254. // Create the result
  255. _result = new ScenarioResult(_testMethod, _testClass, res, excp);
  256. SetResultTimes();
  257. // If an asynchronous method, do not run any additional parts of the method container
  258. if (_mainTestMethodContainer.RemainingWork)
  259. {
  260. while (_mainTestMethodContainer.RemainingWork)
  261. {
  262. _mainTestMethodContainer.Dequeue();
  263. }
  264. }
  265. }
  266. /// <summary>
  267. /// Create a new method container to enclose a reflected method for execution.
  268. /// </summary>
  269. /// <param name="method">The method reflection object.</param>
  270. private void EnqueueMethodDispatcher(MethodInfo method)
  271. {
  272. Enqueue(new UnitTestMethodContainer(TestHarness, _instance, method, null, TestGranularity.TestScenario));
  273. }
  274. }
  275. }