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

Datarow tests - support methods with optional parameters and add params support #604

Merged
merged 7 commits into from
May 7, 2019
89 changes: 88 additions & 1 deletion src/Adapter/MSTest.CoreAdapter/Execution/TestMethodInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,94 @@ public virtual TestResult Invoke(object[] arguments)

internal void SetArguments(object[] arguments)
{
this.arguments = arguments;
if (arguments == null)
{
this.arguments = null;
}
else
{
this.arguments = this.ResolveArguments(arguments);
}
}

internal object[] ResolveArguments(object[] arguments)
jayaranigarg marked this conversation as resolved.
Show resolved Hide resolved
{
ParameterInfo[] parameterInfos = this.TestMethod.GetParameters();
int requiredParameterCount = 0;
bool hasParamsValue = false;
object paramsValues = null;
foreach (var parameter in parameterInfos)
{
// If this is a params array parameter, create an instance to
// populate with any extra values provided. Don't increment
// required parameter count - params arguments are not actually required
if (parameter.GetCustomAttribute(typeof(ParamArrayAttribute)) != null)
{
hasParamsValue = true;
break;
}

// Count required parameters from method
if (!parameter.IsOptional)
{
requiredParameterCount++;
}
}

// If all the parameters are required, we have fewer arguments
// supplied than required, or more arguments than the method takes
// and it doesn't have a params paramenter don't try and resolve anything
if (requiredParameterCount == parameterInfos.Length ||
arguments.Length < requiredParameterCount ||
(!hasParamsValue && arguments.Length > parameterInfos.Length))
{
return arguments;
}

object[] newParameters = new object[parameterInfos.Length];
for (int argumentIndex = 0; argumentIndex < arguments.Length; argumentIndex++)
{
// We have reached the end of the regular parameters and any additional
// values will go in a params array
if (argumentIndex >= parameterInfos.Length - 1 && hasParamsValue)
{
// If this is the params parameter, instantiate a new object of that type
if (argumentIndex == parameterInfos.Length - 1)
{
paramsValues = Activator.CreateInstance(parameterInfos[argumentIndex].ParameterType, new object[] { arguments.Length - argumentIndex });
newParameters[argumentIndex] = paramsValues;
}

// The params parameters is an array but the type is not known
// set the values as a generic array
if (paramsValues is Array paramsArray)
{
paramsArray.SetValue(arguments[argumentIndex], argumentIndex - (parameterInfos.Length - 1));
}
}
else
{
newParameters[argumentIndex] = arguments[argumentIndex];
}
}

// If arguments supplied are less than total possible arguments set
// the values supplied to the default values for those parameters
for (int parameterNotProvidedIndex = arguments.Length; parameterNotProvidedIndex < parameterInfos.Length; parameterNotProvidedIndex++)
{
// If this is the params parameters, set it to an empty
// array of that type as DefaultValue is DBNull
if (hasParamsValue && parameterNotProvidedIndex == parameterInfos.Length - 1)
{
newParameters[parameterNotProvidedIndex] = Activator.CreateInstance(parameterInfos[parameterNotProvidedIndex].ParameterType, 0);
}
else
{
newParameters[parameterNotProvidedIndex] = parameterInfos[parameterNotProvidedIndex].DefaultValue;
}
}

return newParameters;
}

/// <summary>
Expand Down
8 changes: 8 additions & 0 deletions src/TestFramework/MSTest.Core/Attributes/DataRowAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class DataRowAttribute : Attribute, ITestDataSource
{
/// <summary>
/// Initializes a new instance of the <see cref="DataRowAttribute"/> class.
/// </summary>
public DataRowAttribute()
{
this.Data = new object[0];
}

/// <summary>
/// Initializes a new instance of the <see cref="DataRowAttribute"/> class.
/// </summary>
Expand Down
72 changes: 65 additions & 7 deletions test/E2ETests/Smoke.E2E.Tests/DataRowTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ public class DataRowTests : CLITestBase
private const string TestAssembly = "DataRowTestProject.dll";

[TestMethod]
public void ExecuteOnlyDerivedClassDataRowsWhenBothBaseAndDerviedClassHasDataRows()
public void ExecuteOnlyDerivedClassDataRowsWhenBothBaseAndDerviedClassHasDataRows_SimpleDataRows()
{
this.InvokeVsTestForExecution(new string[] { TestAssembly });
this.InvokeVsTestForExecution(new string[] { TestAssembly }, testCaseFilter: "TestCategory~DataRowSimple");

this.ValidatePassedTestsContain(
"DataRowTestMethod (BaseString1)",
Expand All @@ -23,23 +23,81 @@ public void ExecuteOnlyDerivedClassDataRowsWhenBothBaseAndDerviedClassHasDataRow
"DataRowTestMethod (DerivedString1)",
"DataRowTestMethod (DerivedString2)");

// 4 tests of BaseClass - 3 datarow result and 1 parent result
// 3 tests of DerivedClass - 2 datarow result and 1 parent result
// 4 tests of BaseClass.DataRowTestMethod - 3 datarow result and 1 parent result
// 3 tests of DerivedClass.DataRowTestMethod - 2 datarow result and 1 parent result
// Total 7 tests - Making sure that DerivedClass doesn't run BaseClass tests
this.ValidatePassedTestsCount(7);
}

[TestMethod]
public void ExecuteOnlyDerivedClassDataRowsWhenItOverridesBaseClassDataRows()
public void ExecuteOnlyDerivedClassDataRowsWhenItOverridesBaseClassDataRows_SimpleDataRows()
{
this.InvokeVsTestForExecution(new string[] { TestAssembly }, testCaseFilter: "FullyQualifiedName~DerivedClass");
this.InvokeVsTestForExecution(new string[] { TestAssembly }, testCaseFilter: "FullyQualifiedName~DerivedClass&TestCategory~DataRowSimple");

this.ValidatePassedTestsContain(
"DataRowTestMethod (DerivedString1)",
"DataRowTestMethod (DerivedString2)");

// 3 tests of DerivedClass - 2 datarow result and 1 parent result
// 3 tests of DerivedClass.DataRowTestMethod - 2 datarow result and 1 parent result
this.ValidatePassedTestsCount(3);
}

[TestMethod]
public void DataRowsExecuteWithRequiredAndOptionalParameters()
{
this.InvokeVsTestForExecution(new string[] { TestAssembly }, testCaseFilter: "TestCategory~DataRowSomeOptional");

this.ValidatePassedTestsContain(
"DataRowTestMethodWithSomeOptionalParameters (123)",
"DataRowTestMethodWithSomeOptionalParameters (123,DerivedOptionalString1)",
"DataRowTestMethodWithSomeOptionalParameters (123,DerivedOptionalString2,DerivedOptionalString3)");

// 4 tests of DerivedClass.DataRowTestMethodWithSomeOptionalParameters - 3 datarow result and 1 parent result
jayaranigarg marked this conversation as resolved.
Show resolved Hide resolved
this.ValidatePassedTestsCount(4);
}

[TestMethod]
public void DataRowsExecuteWithAllOptionalParameters()
{
this.InvokeVsTestForExecution(new string[] { TestAssembly }, testCaseFilter: "TestCategory~DataRowAllOptional");

this.ValidatePassedTestsContain(
"DataRowTestMethodWithAllOptionalParameters ()",
"DataRowTestMethodWithAllOptionalParameters (123)",
jayaranigarg marked this conversation as resolved.
Show resolved Hide resolved
"DataRowTestMethodWithAllOptionalParameters (123,DerivedOptionalString4)",
"DataRowTestMethodWithAllOptionalParameters (123,DerivedOptionalString5,DerivedOptionalString6)");

// 5 tests of DerivedClass.DataRowTestMethodWithAllOptionalParameters - 4 datarow result and 1 parent result
this.ValidatePassedTestsCount(5);
}

[TestMethod]
public void DataRowsExecuteWithParamsArrayParameter()
{
this.InvokeVsTestForExecution(new string[] { TestAssembly }, testCaseFilter: "TestCategory~DataRowParamsArgument");

this.ValidatePassedTestsContain(
"DataRowTestMethodWithParamsParameters (2)",
"DataRowTestMethodWithParamsParameters (2,DerivedSingleParamsArg)",
"DataRowTestMethodWithParamsParameters (2,DerivedParamsArg1,DerivedParamsArg2)",
"DataRowTestMethodWithParamsParameters (2,DerivedParamsArg1,DerivedParamsArg2,DerivedParamsArg3)");

// 5 tests of DerivedClass.DataRowTestMethodWithParamsParameters - 4 datarow result and 1 parent result
this.ValidatePassedTestsCount(5);
}

[TestMethod]
public void DataRowsFailWhenInvalidArgumentsProvided()
{
this.InvokeVsTestForExecution(new string[] { TestAssembly }, testCaseFilter: "TestCategory~DataRowOptionalInvalidArguments");

this.ValidatePassedTestsContain(
"DataRowTestMethodFailsWithInvalidArguments ()",
"DataRowTestMethodFailsWithInvalidArguments (2)",
"DataRowTestMethodFailsWithInvalidArguments (2,DerivedRequiredArgument,DerivedOptionalArgument,DerivedExtraArgument)");

// 4 tests of DerivedClass.DataRowTestMethodFailsWithInvalidArguments - 3 datarow result and 1 parent result
this.ValidatePassedTestsCount(4);
}
}
}
1 change: 1 addition & 0 deletions test/E2ETests/TestAssets/DataRowTestProject/BaseClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace DataRowTestProject
[TestClass]
public class BaseClass
{
[TestCategory("DataRowSimple")]
[TestMethod]
[DataRow("BaseString1")]
[DataRow("BaseString2")]
Expand Down
44 changes: 44 additions & 0 deletions test/E2ETests/TestAssets/DataRowTestProject/DerivedClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,56 @@ namespace DataRowTestProject
[TestClass]
public class DerivedClass : BaseClass
{
[TestCategory("DataRowSimple")]
[TestMethod]
[DataRow("DerivedString1")]
[DataRow("DerivedString2")]
public override void DataRowTestMethod(string a)
{
Assert.IsTrue(true);
}

[TestCategory("DataRowSomeOptional")]
[TestMethod]
[DataRow(123)]
[DataRow(123, "DerivedOptionalString1")]
[DataRow(123, "DerivedOptionalString2", "DerivedOptionalString3")]
public void DataRowTestMethodWithSomeOptionalParameters(int i, string s1 = null, string s2 = null)
{
Assert.IsTrue(true);
}

[TestCategory("DataRowAllOptional")]
[TestMethod]
[DataRow()]
[DataRow(123)]
[DataRow(123, "DerivedOptionalString4")]
[DataRow(123, "DerivedOptionalString5", "DerivedOptionalString6")]
public void DataRowTestMethodWithAllOptionalParameters(int i = 0, string s1 = null, string s2 = null)
{
Assert.IsTrue(true);
}

[TestCategory("DataRowParamsArgument")]
[TestMethod]
[DataRow(2)]
[DataRow(2, "DerivedSingleParamsArg")]
[DataRow(2, "DerivedParamsArg1", "DerivedParamsArg2")]
[DataRow(2, "DerivedParamsArg1", "DerivedParamsArg2","DerivedParamsArg3")]
public void DataRowTestMethodWithParamsParameters(int i, params string[] args)
{
Assert.IsTrue(true);
}

[TestCategory("DataRowOptionalInvalidArguments")]
[TestMethod]
[ExpectedException(typeof(System.Reflection.TargetParameterCountException))]
[DataRow()]
[DataRow(2)]
[DataRow(2, "DerivedRequiredArgument", "DerivedOptionalArgument", "DerivedExtraArgument")]
public void DataRowTestMethodFailsWithInvalidArguments(int i1, string requiredString, string s1 = null)
{
Assert.Fail();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ public class DataRowAttributeTests
private DummyTestClass dummyTestClass;
private MethodInfo testMethodInfo;

[TestMethod]
public void DefaultConstructorSetsEmptyArrayPassed()
{
var dataRow = new DataRowAttribute();

CollectionAssert.AreEqual(new object[] { }, dataRow.Data);
}

[TestMethod]
public void ConstructorShouldSetDataPassed()
{
Expand Down
Loading