Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataSourceAttribute Implementation #238

Merged
merged 8 commits into from
Sep 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions src/Adapter/MSTest.CoreAdapter/Execution/TestMethodInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class TestMethodInfo : ITestMethod
/// </summary>
public const int TimeoutWhenNotSet = 0;

private object[] arguments;

internal TestMethodInfo(
MethodInfo testMethod,
TestClassInfo parent,
Expand Down Expand Up @@ -55,21 +57,18 @@ internal TestMethodInfo(
/// </summary>
public bool IsRunnable => string.IsNullOrEmpty(this.NotRunnableReason);

/// <inheritdoc/>
public ParameterInfo[] ParameterTypes => this.TestMethod.GetParameters();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why removed /// <inheritdoc/>?


/// <inheritdoc/>
public Type ReturnType => this.TestMethod.ReturnType;

/// <inheritdoc/>
public string TestClassName => this.Parent.ClassType.FullName;

/// <inheritdoc/>
public string TestMethodName => this.TestMethod.Name;

/// <inheritdoc/>
public MethodInfo MethodInfo => this.TestMethod;

public object[] Arguments => this.arguments;

/// <summary>
/// Gets testMethod referred by this object
/// </summary>
Expand All @@ -85,13 +84,11 @@ internal TestMethodInfo(
/// </summary>
internal TestMethodOptions TestMethodOptions { get; private set; }

/// <inheritdoc/>
public Attribute[] GetAllAttributes(bool inherit)
{
return ReflectHelper.GetCustomAttributes(this.TestMethod, inherit) as Attribute[];
}

/// <inheritdoc/>
public TAttributeType[] GetAttributes<TAttributeType>(bool inherit)
where TAttributeType : Attribute
{
Expand Down Expand Up @@ -119,14 +116,24 @@ public TAttributeType[] GetAttributes<TAttributeType>(bool inherit)
return tAttributeList.ToArray();
}

/// <inheritdoc/>
/// <remarks>
/// <summary>
/// Execute test method. Capture failures, handle async and return result.
/// </remarks>
/// </summary>
/// <param name="arguments">
/// Arguments to pass to test method. (E.g. For data driven)
/// </param>
/// <returns>Result of test method invocation.</returns>
public virtual TestResult Invoke(object[] arguments)
{
Stopwatch watch = new Stopwatch();
TestResult result = null;

// check if arguments are set for data driven tests
if (arguments == null)
{
arguments = this.Arguments;
}

using (LogMessageListener listener = new LogMessageListener(this.TestMethodOptions.CaptureDebugTraces))
{
watch.Start();
Expand Down Expand Up @@ -161,6 +168,11 @@ public virtual TestResult Invoke(object[] arguments)
return result;
}

internal void SetArguments(object[] arguments)
{
this.arguments = arguments;
}

/// <summary>
/// Execute test without timeout.
/// </summary>
Expand Down
123 changes: 105 additions & 18 deletions src/Adapter/MSTest.CoreAdapter/Execution/TestMethodRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;

using Extensions;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;

using UTF = Microsoft.VisualStudio.TestTools.UnitTesting;

/// <summary>
Expand Down Expand Up @@ -214,36 +214,123 @@ internal UnitTestResult[] RunTestMethod()
Debug.Assert(this.test != null, "Test should not be null.");
Debug.Assert(this.testMethodInfo.TestMethod != null, "Test method should not be null.");

UTF.TestResult[] results = null;
List<UTF.TestResult> results = new List<UTF.TestResult>();

if (this.testMethodInfo.TestMethodOptions.Executor != null)
{
try
UTF.DataSourceAttribute[] dataSourceAttribute = this.testMethodInfo.GetAttributes<UTF.DataSourceAttribute>(false);
if (dataSourceAttribute != null && dataSourceAttribute.Length == 1)
{
bool isDataDriven = PlatformServiceProvider.Instance.TestDataSource.HasDataDrivenTests(this.testMethodInfo);
if (isDataDriven)
Stopwatch watch = new Stopwatch();
watch.Start();

try
{
results = PlatformServiceProvider.Instance.TestDataSource.RunDataDrivenTest(this.testContext.Context, this.testMethodInfo, this.test, this.testMethodInfo.TestMethodOptions.Executor);
IEnumerable<object> dataRows = PlatformServiceProvider.Instance.TestDataSource.GetData(this.testMethodInfo, this.testContext);

if (dataRows == null)
{
watch.Stop();
var inconclusiveResult = new UTF.TestResult();
inconclusiveResult.Outcome = UTF.UnitTestOutcome.Inconclusive;
inconclusiveResult.Duration = watch.Elapsed;
results.Add(inconclusiveResult);
}
else
{
try
{
int rowIndex = 0;
foreach (object dataRow in dataRows)
{
watch.Reset();
watch.Start();

this.testContext.SetDataRow(dataRow);
UTF.TestResult currentResult;

try
{
currentResult = this.testMethodInfo.TestMethodOptions.Executor.Execute(this.testMethodInfo)[0];
}
catch (Exception ex)
{
currentResult = new UTF.TestResult() { TestFailureException = new Exception(string.Format(CultureInfo.CurrentCulture, Resource.UTA_ExecuteThrewException, ex.Message), ex) };
}

currentResult.DatarowIndex = rowIndex++;
watch.Stop();
currentResult.Duration = watch.Elapsed;

results.Add(currentResult);
}
}
finally
{
this.testContext.SetDataConnection(null);
this.testContext.SetDataRow(null);
}
}
}
else
catch (Exception ex)
{
results = this.testMethodInfo.TestMethodOptions.Executor.Execute(this.testMethodInfo);
watch.Stop();
var failedResult = new UTF.TestResult();
failedResult.Outcome = UTF.UnitTestOutcome.Error;
failedResult.TestFailureException = ex;
failedResult.Duration = watch.Elapsed;
results.Add(failedResult);
}
}
catch (Exception ex)
else
{
results = new[] { new UTF.TestResult() { TestFailureException = new Exception(string.Format(CultureInfo.CurrentCulture, Resource.UTA_ExecuteThrewException, ex.Message), ex) } };
UTF.ITestDataSource[] testDataSources = this.testMethodInfo.GetAttributes<Attribute>(true)?.Where(a => a is UTF.ITestDataSource).OfType<UTF.ITestDataSource>().ToArray();

if (testDataSources != null && testDataSources.Length > 0)
{
foreach (var testDataSource in testDataSources)
{
foreach (var data in testDataSource.GetData(this.testMethodInfo.MethodInfo))
{
this.testMethodInfo.SetArguments(data);
UTF.TestResult currentResult;
try
{
currentResult = this.testMethodInfo.TestMethodOptions.Executor.Execute(this.testMethodInfo)[0];
}
catch (Exception ex)
{
currentResult = new UTF.TestResult() { TestFailureException = new Exception(string.Format(CultureInfo.CurrentCulture, Resource.UTA_ExecuteThrewException, ex.Message), ex) };
}

currentResult.DisplayName = testDataSource.GetDisplayName(this.testMethodInfo.MethodInfo, data);
results.Add(currentResult);
this.testMethodInfo.SetArguments(null);
}
}
}
else
{
try
{
results.Add(this.testMethodInfo.TestMethodOptions.Executor.Execute(this.testMethodInfo)[0]);
}
catch (Exception ex)
{
results.Add(new UTF.TestResult() { TestFailureException = new Exception(string.Format(CultureInfo.CurrentCulture, Resource.UTA_ExecuteThrewException, ex.Message), ex) });
}
}
}
}
else
{
PlatformServiceProvider.Instance.AdapterTraceLogger.LogError(
"Not able to get executor for method {0}.{1}",
this.testMethodInfo.TestClassName,
this.testMethodInfo.TestMethodName);
"Not able to get executor for method {0}.{1}",
this.testMethodInfo.TestClassName,
this.testMethodInfo.TestMethodName);
}

if (results != null && results.Length > 0)
if (results != null && results.Count > 0)
{
// aggregate for data driven tests
UTF.UnitTestOutcome aggregateOutcome = UTF.UnitTestOutcome.Passed;
Expand All @@ -268,10 +355,10 @@ internal UnitTestResult[] RunTestMethod()
else
{
this.testContext.SetOutcome(UTF.UnitTestOutcome.Unknown);
results = new[] { new UTF.TestResult() { Outcome = UTF.UnitTestOutcome.Unknown, TestFailureException = new TestFailedException(UnitTestOutcome.Error, Resource.UTA_NoTestResult) } };
results.Add(new UTF.TestResult() { Outcome = UTF.UnitTestOutcome.Unknown, TestFailureException = new TestFailedException(UnitTestOutcome.Error, Resource.UTA_NoTestResult) });
}

return results.ToUnitTestResults();
return results.ToArray().ToUnitTestResults();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,24 @@ public void SetOutcome(UTF.UnitTestOutcome outcome)
this.outcome = ToUTF(outcome);
}

/// <summary>
/// Set data row for particular run of TestMethod.
/// </summary>
/// <param name="dataRow">data row.</param>
public void SetDataRow(object dataRow)
{
this.dataRow = dataRow as DataRow;
}

/// <summary>
/// Set connection for TestContext
/// </summary>
/// <param name="dbConnection">db Connection.</param>
public void SetDataConnection(object dbConnection)
{
this.dbConnection = dbConnection as DbConnection;
}

/// <summary>
/// Returns whether property with parameter name is present or not
/// </summary>
Expand Down Expand Up @@ -377,28 +395,6 @@ public void ClearDiagnosticMessages()

#endregion

#region internal methods

/// <summary>
/// Set connection for TestContext
/// </summary>
/// <param name="dbConnection">db Connection.</param>
internal void SetDataConnection(DbConnection dbConnection)
{
this.dbConnection = dbConnection;
}

/// <summary>
/// Set data row for particular run of Windows Store app.
/// </summary>
/// <param name="dataRow">data row</param>
internal void SetDataRow(DataRow dataRow)
{
this.dataRow = dataRow;
}

#endregion

/// <summary>
/// Converts the parameter outcome to UTF outcome
/// </summary>
Expand Down
Loading