/// <summary> /// Resolve the test method. The function will try to /// find a function that has the method name with 0 parameters. If the function /// cannot be found, or a function is found that returns non-void, the result is /// set to error. /// </summary> /// <param name="testMethod"> The test Method. </param> /// <param name="testClassInfo"> The test Class Info. </param> /// <param name="testContext"> The test Context. </param> /// <param name="captureDebugTraces"> Indicates whether the test method should capture debug traces.</param> /// <returns> /// The TestMethodInfo for the given test method. Null if the test method could not be found. /// </returns> private TestMethodInfo ResolveTestMethod(TestMethod testMethod, TestClassInfo testClassInfo, ITestContext testContext, bool captureDebugTraces) { Debug.Assert(testMethod != null, "testMethod is Null"); Debug.Assert(testClassInfo != null, "testClassInfo is Null"); var methodInfo = this.GetMethodInfoForTestMethod(testMethod, testClassInfo); if (methodInfo == null) { // Means the specified test method could not be found. return(null); } var expectedExceptionAttribute = this.reflectionHelper.ResolveExpectedExceptionHelper(methodInfo, testMethod); var timeout = this.GetTestTimeout(methodInfo, testMethod); var testMethodOptions = new TestMethodOptions() { Timeout = timeout, Executor = this.GetTestMethodAttribute(methodInfo, testClassInfo), ExpectedException = expectedExceptionAttribute, TestContext = testContext, CaptureDebugTraces = captureDebugTraces }; var testMethodInfo = new TestMethodInfo(methodInfo, testClassInfo, testMethodOptions); this.SetCustomProperties(testMethodInfo, testContext); return(testMethodInfo); }
/// <summary> /// Whether the given testMethod is runnable /// </summary> /// <param name="testMethod">The testMethod</param> /// <param name="testMethodInfo">The testMethodInfo</param> /// <param name="notRunnableResult">The results to return if the test method is not runnable</param> /// <returns>whether the given testMethod is runnable</returns> private bool IsTestMethodRunnable( TestMethod testMethod, TestMethodInfo testMethodInfo, out UnitTestResult[] notRunnableResult) { // If the specified TestMethod could not be found, return a NotFound result. if (testMethodInfo == null) { { notRunnableResult = new UnitTestResult[] { new UnitTestResult( ObjectModel.UnitTestOutcome.NotFound, string.Format(CultureInfo.CurrentCulture, Resource.TestNotFound, testMethod.Name)) }; return(false); } } // If test cannot be executed, then bail out. if (!testMethodInfo.IsRunnable) { { notRunnableResult = new UnitTestResult[] { new UnitTestResult(ObjectModel.UnitTestOutcome.NotRunnable, testMethodInfo.NotRunnableReason) }; return(false); } } string ignoreMessage = null; var isIgnoreAttributeOnClass = this.reflectHelper.IsAttributeDefined(testMethodInfo.Parent.ClassType, typeof(UTF.IgnoreAttribute), false); var isIgnoreAttributeOnMethod = this.reflectHelper.IsAttributeDefined(testMethodInfo.TestMethod, typeof(UTF.IgnoreAttribute), false); if (isIgnoreAttributeOnClass) { ignoreMessage = this.reflectHelper.GetIgnoreMessage(testMethodInfo.Parent.ClassType.GetTypeInfo()); } if (string.IsNullOrEmpty(ignoreMessage) && isIgnoreAttributeOnMethod) { ignoreMessage = this.reflectHelper.GetIgnoreMessage(testMethodInfo.TestMethod); } if (isIgnoreAttributeOnClass || isIgnoreAttributeOnMethod) { { notRunnableResult = new[] { new UnitTestResult(ObjectModel.UnitTestOutcome.Ignored, ignoreMessage) }; return(false); } } notRunnableResult = null; return(true); }
/// <summary> /// Initializes a new instance of the <see cref="TestMethodRunner"/> class. /// </summary> /// <param name="testMethodInfo"> /// The test method info. /// </param> /// <param name="testMethod"> /// The test method. /// </param> /// <param name="testContext"> /// The test context. /// </param> /// <param name="captureDebugTraces"> /// The capture debug traces. /// </param> /// <param name="reflectHelper"> /// The reflect Helper object. /// </param> public TestMethodRunner(TestMethodInfo testMethodInfo, TestMethod testMethod, ITestContext testContext, bool captureDebugTraces, ReflectHelper reflectHelper) { Debug.Assert(testMethodInfo != null, "testMethodInfo should not be null"); Debug.Assert(testMethod != null, "testMethod should not be null"); Debug.Assert(testContext != null, "testContext should not be null"); this.testMethodInfo = testMethodInfo; this.test = testMethod; this.testContext = testContext; this.captureDebugTraces = captureDebugTraces; this.reflectHelper = reflectHelper; }
public void MarkTestComplete(TestMethodInfo testMethod, out bool shouldCleanup) { shouldCleanup = false; var testsByClass = this.remainingTestsByClass[testMethod.TestClassName]; lock (testsByClass) { testsByClass.Remove(testMethod.TestMethodName); if (testsByClass.Count == 0 && testMethod.Parent.HasExecutableCleanupMethod) { var cleanupLifecycle = this.reflectHelper.GetClassCleanupSequence(testMethod.Parent.ClassType.GetTypeInfo()) ?? this.lifecycleFromMsTest ?? this.lifecycleFromAssembly; shouldCleanup = cleanupLifecycle == ClassCleanupLifecycle.EndOfClass; } } }
/// <summary> /// Set custom properties /// </summary> /// <param name="testMethodInfo"> The test Method Info. </param> /// <param name="testContext"> The test Context. </param> private void SetCustomProperties(TestMethodInfo testMethodInfo, ITestContext testContext) { Debug.Assert(testMethodInfo != null, "testMethodInfo is Null"); Debug.Assert(testMethodInfo.TestMethod != null, "testMethodInfo.TestMethod is Null"); var attributes = testMethodInfo.TestMethod.GetCustomAttributes(typeof(TestPropertyAttribute), false); Debug.Assert(attributes != null, "attributes is null"); foreach (TestPropertyAttribute attribute in attributes) { if (!this.ValidateAndAssignTestProperty(testMethodInfo, testContext, attribute.Name, attribute.Value)) { break; } } }
private UTF.TestResult[] ExecuteTest(TestMethodInfo testMethodInfo) { try { return(this.testMethodInfo.TestMethodOptions.Executor.Execute(testMethodInfo)); } catch (Exception ex) { return(new[] { new UTF.TestResult() { TestFailureException = new Exception(string.Format(CultureInfo.CurrentCulture, Resource.UTA_ExecuteThrewException, ex?.Message, ex?.StackTrace), ex) } }); } }
/// <summary> /// Validates If a Custom test property is valid and then adds it to the TestContext property list. /// </summary> /// <param name="testMethodInfo"> The test method info. </param> /// <param name="testContext"> The test context. </param> /// <param name="propertyName"> The property name. </param> /// <param name="propertyValue"> The property value. </param> /// <returns> True if its a valid Test Property. </returns> private bool ValidateAndAssignTestProperty( TestMethodInfo testMethodInfo, ITestContext testContext, string propertyName, string propertyValue) { if (PredefinedNames.Any(predefinedProp => predefinedProp == propertyName)) { testMethodInfo.NotRunnableReason = string.Format( CultureInfo.CurrentCulture, Resource.UTA_ErrorPredefinedTestProperty, testMethodInfo.TestMethod.DeclaringType.FullName, testMethodInfo.TestMethod.Name, propertyName); return(false); } if (string.IsNullOrEmpty(propertyName)) { testMethodInfo.NotRunnableReason = string.Format( CultureInfo.CurrentCulture, Resource.UTA_ErrorTestPropertyNullOrEmpty, testMethodInfo.TestMethod.DeclaringType.FullName, testMethodInfo.TestMethod.Name); return(false); } object existingValue; if (testContext.TryGetPropertyValue(propertyName, out existingValue)) { // Do not add to the test context because it would conflict with an already existing value. // We were at one point reporting a warning here. However with extensibility centered around TestProperty where // users can have multiple WorkItemAttributes(say) we cannot throw a warning here. Users would have multiple of these attributes // so that it shows up in reporting rather than seeing them in TestContext properties. } else { testContext.AddProperty(propertyName, propertyValue); } return(true); }
private void RunClassCleanupIfEndOfClass(TestMethodInfo testMethodInfo, TestMethod testMethod, UnitTestResult[] results) { bool shouldRunClassCleanup = false; this.classCleanupManager?.MarkTestComplete(testMethodInfo, testMethod, out shouldRunClassCleanup); if (shouldRunClassCleanup) { string cleanupLogs = string.Empty; string cleanupTrace = string.Empty; string cleanupErrorLogs = string.Empty; try { using (LogMessageListener logListener = new LogMessageListener(MSTestSettings.CurrentSettings.CaptureDebugTraces)) { try { // Class cleanup can throw exceptions in which case we need to ensure that we fail the test. testMethodInfo.Parent.RunClassCleanup(ClassCleanupBehavior.EndOfClass); } finally { cleanupLogs = logListener.StandardOutput; cleanupTrace = logListener.DebugTrace; cleanupErrorLogs = logListener.StandardError; var lastResult = results[results.Length - 1]; lastResult.StandardOut = lastResult.StandardOut + cleanupLogs; lastResult.StandardError = lastResult.StandardError + cleanupErrorLogs; lastResult.DebugTrace = lastResult.DebugTrace + cleanupTrace; } } } catch (Exception e) { results[results.Length - 1].Outcome = ObjectModel.UnitTestOutcome.Failed; results[results.Length - 1].ErrorMessage = e.Message; results[results.Length - 1].ErrorStackTrace = e.StackTrace; } } }
/// <summary> /// Initializes a new instance of the <see cref="TestMethodRunner"/> class. /// </summary> /// <param name="testMethodInfo"> /// The test method info. /// </param> /// <param name="testMethod"> /// The test method. /// </param> /// <param name="testContext"> /// The test context. /// </param> /// <param name="captureDebugTraces"> /// The capture debug traces. /// </param> public TestMethodRunner(TestMethodInfo testMethodInfo, TestMethod testMethod, ITestContext testContext, bool captureDebugTraces) : this(testMethodInfo, testMethod, testContext, captureDebugTraces, ReflectHelper.Instance) { }