/// <summary> /// The method that gets called when a test is executed /// </summary> /// <param name="args">arguments that are passed from the test signature</param> /// <returns></returns> public TestMethodInvokerResult Invoke(params object[] args) { // Our helper results class to aggregate our test results // Make sure we dispose it when done to get rid of our XmlTextWriter using (HelperTestGridResults results = new HelperTestGridResults(this.invokerContext.TestMethodInfo)) { Assembly testMethodAssembly = this.invokerContext.TestMethodInfo.DeclaringType.Assembly; // Gets the custom attribute off the method RowAttribute[] rows = (RowAttribute[])this.invokerContext.TestMethodInfo.GetCustomAttributes(typeof(RowAttribute), false); IList<RowFilterAttribute> rowFilters = AttributeHelper.GetCustomAttributes<RowFilterAttribute>(this.invokerContext.TestMethodInfo, true); IList<TestExecutionAttribute> testExecutionAttributes = AttributeHelper.GetCustomAttributes<TestExecutionAttribute>(this.invokerContext.TestMethodInfo, true); TestExecutionAttribute testExecutionAggregateAttr = TestExecutionAttribute.Aggregate(testExecutionAttributes); Log.LogWriter logWriter = CreateLogWriter(testExecutionAggregateAttr); SetExpandedPaths(rows, this.invokerContext); IEnumerable<DataRowValues> dataRowValuesCollection = GetAllDataRowValues(rows, this.invokerContext, results); IEnumerable<RowTestContext> inputRowContexts = dataRowValuesCollection.Select(dataRowValues => { object[] valuesArray = results.PrepareRowValues(dataRowValues); RowTestContext rowTestContext = new RowTestContext(dataRowValues) { LogType = testExecutionAggregateAttr.LogType, LogContentType = testExecutionAggregateAttr.LogContentType, LogWriter = logWriter, WriteHeaders = testExecutionAggregateAttr.WriteHeaders, ValuesArray = valuesArray, TestExecutionAttributes = testExecutionAttributes }; PopulateRowSkippedInfo(invokerContext, rowTestContext, rowFilters); return rowTestContext; }); IEnumerable<RowTestContext> outputRowContexts; if (testExecutionAggregateAttr.ExecuteInParallel) { ParallelQuery<RowTestContext> query = inputRowContexts.AsParallel().AsOrdered(); if (testExecutionAggregateAttr.MaxDegreeOfParallelism > 0) { query = query.WithDegreeOfParallelism(testExecutionAggregateAttr.MaxDegreeOfParallelism); } outputRowContexts = query.Select(this.InvokeSingleRow); } else { outputRowContexts = inputRowContexts.Select(this.InvokeSingleRow); } // enumerate row data and invoke the test case with each yield they give us foreach (RowTestContext rowTestContext in outputRowContexts) { // Add results to our aggregator if it is either executed, or skipped but we are showing skipped rows in results if (!rowTestContext.Ignored || rowTestContext.ShowSkipped) { results.AddTestResult(rowTestContext); } } // Return the aggregated results for the row variatons in the TestMethod return results.GetAllResults(); } }
private static void PopulateRowSkippedInfo(TestMethodInvokerContext invokerContext, RowTestContext rowTestContext, IList<RowFilterAttribute> filters) { FilterInfo filterInfo = filters.Select(filter => filter.GetFilterInfo(invokerContext, rowTestContext.DataRowValues)) .Aggregate(FilterInfo.None, (acc, f) => acc | f); rowTestContext.Ignored = false; rowTestContext.ShowSkipped = true; // Process execution flags. if ((filterInfo & FilterInfo.Exclude) != FilterInfo.None) { rowTestContext.Ignored = true; } if ((filterInfo & FilterInfo.Include) != FilterInfo.None) { rowTestContext.Ignored = false; } // Process display flags if ((filterInfo & FilterInfo.HideSkipped) != FilterInfo.None) { rowTestContext.ShowSkipped = false; } if ((filterInfo & FilterInfo.ShowSkipped) != FilterInfo.None) { rowTestContext.ShowSkipped = true; } if (rowTestContext.DataRowValues.Ignore) { rowTestContext.Ignored = true; } }
private RowTestContext InvokeSingleRow(RowTestContext rowTestContext) { if (rowTestContext.Ignored) { return rowTestContext; } if (rowTestContext.LogType == Log.LogDetailsType.RowDetails) { rowTestContext.LogBuilder = new StringBuilder(); rowTestContext.LogWriter = Log.LogWriter.CreateStringBuilderLogWriter(rowTestContext.LogBuilder, rowTestContext.LogType, rowTestContext.LogContentType); } if (rowTestContext.WriteHeaders) { if (rowTestContext.LogContentType == Log.LogDetailsContentType.Html) { rowTestContext.LogWriter.WriteLine("<pre>"); rowTestContext.LogWriter.Write("<b>"); } // Output header info as to which data input row we are now on, // so any WriteLines or exception messages are diusplayed in-context under it. // This is the best we can do to partition the output per data input row, since MSTest does not know // that one of its Testmethods is really logically broken down into N rows. rowTestContext.LogWriter.Write("[Test {0}] {1}", rowTestContext.DataRowValues.Id, rowTestContext.DataRowValues.Desc); if (rowTestContext.LogContentType == Log.LogDetailsContentType.Html) { rowTestContext.LogWriter.Write("</b>"); } rowTestContext.LogWriter.WriteLine(string.Empty); } // Execute the parameterize test method for the current data input row values we parsed. // The invocation context will have a non-null Exception property if something threw within it // (since MSTest catches it first to record it for their purposes). // So no try/catch wrapper or rethrowing is necessary on our part. RowTestContext.Current = rowTestContext; // Give every TestExecutionAttribute an option to override default Test Method Invoker. ITestMethodInvoker testMethodInvoker = rowTestContext.TestExecutionAttributes.Aggregate( this.invokerContext.InnerInvoker, (ITestMethodInvoker invoker, TestExecutionAttribute attr) => attr.OverrideTestMethodInvoker(invoker, this.invokerContext, rowTestContext)); rowTestContext.InvokerResult = testMethodInvoker.Invoke(rowTestContext.ValuesArray); RowTestContext.Current = null; rowTestContext.ResultException = rowTestContext.InvokerResult.Exception; // Use the inner exception as the meaningful one for us, unless there isn't one. // Normally the "target of invocation" outer exception is just noise for our purposes, // unless there is nothing else to show. if (rowTestContext.ResultException != null && rowTestContext.ResultException.GetType() == typeof(TargetInvocationException) && rowTestContext.ResultException.InnerException != null) { rowTestContext.ResultException = rowTestContext.ResultException.InnerException; } // Check for expected exception. if (rowTestContext.DataRowValues.ExpectedException != null) { if (rowTestContext.ResultException != null) { if (rowTestContext.DataRowValues.ExpectedException.IsAssignableFrom(rowTestContext.ResultException.GetType())) { rowTestContext.ResultException = null; } else { rowTestContext.ResultException = new AssertFailedException("Expected '" + rowTestContext.DataRowValues.ExpectedException.FullName + "' exception, but different exception has been thrown. See inner exception.", rowTestContext.ResultException); } } else { rowTestContext.ResultException = new AssertFailedException("Expected '" + rowTestContext.DataRowValues.ExpectedException.FullName + "' exception, but no exception has been thrown."); } } // Log exception if (rowTestContext.ResultException != null) { rowTestContext.ResultMessage = rowTestContext.ResultException.Message; if (rowTestContext.WriteHeaders) { StringBuilder sb = new StringBuilder(); WriteException(sb, rowTestContext.LogContentType, rowTestContext.ResultException); rowTestContext.LogWriter.WriteLine(sb.ToString()); } } if (rowTestContext.WriteHeaders) { // Output data input row end rowTestContext.LogWriter.WriteStringLine("--------------------------"); rowTestContext.LogWriter.WriteStringLine(string.Empty); if (rowTestContext.LogContentType == Log.LogDetailsContentType.Html) { rowTestContext.LogWriter.WriteStringLine("</pre>"); } } ((Log.LogWriter)rowTestContext.LogWriter).Flush(); if (rowTestContext.LogType == Log.LogDetailsType.RowDetails) { rowTestContext.CustomValues.Add("Details", rowTestContext.LogBuilder.ToString()); rowTestContext.CustomValues.Add("DetailsContentType", rowTestContext.LogContentType.ToString()); } return rowTestContext; }
public override ITestMethodInvoker OverrideTestMethodInvoker(ITestMethodInvoker testMethodInvoker, TestMethodInvokerContext originalInvokerContext, RowTestContext rowTestContext) { return new Invoker() { OriginalInvoker = testMethodInvoker }; }