-
Notifications
You must be signed in to change notification settings - Fork 261
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
Offer alternative to serialization of data #4467
base: main
Are you sure you want to change the base?
Changes from 1 commit
4475789
d5fed9b
f01baa6
f06e4d2
ca492b3
987325a
b9fc0d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -181,17 +181,12 @@ internal UnitTestResult[] RunTestMethod() | |
|
||
bool isDataDriven = false; | ||
var parentStopwatch = Stopwatch.StartNew(); | ||
if (_test.DataType == DynamicDataType.ITestDataSource) | ||
if (TryExecuteITestDataSource(results)) | ||
{ | ||
object?[]? data = DataSerializationHelper.Deserialize(_test.SerializedData); | ||
TestResult[] testResults = ExecuteTestWithDataSource(null, data); | ||
results.AddRange(testResults); | ||
} | ||
else if (TryExecuteDataSourceBasedTests(results)) | ||
{ | ||
isDataDriven = true; | ||
// Do nothing | ||
} | ||
else if (TryExecuteFoldedDataDrivenTests(results)) | ||
else if (TryExecuteDataSourceBasedTests(results) | ||
|| TryExecuteFoldedDataDrivenTests(results)) | ||
{ | ||
isDataDriven = true; | ||
} | ||
|
@@ -254,6 +249,46 @@ internal UnitTestResult[] RunTestMethod() | |
return results.ToUnitTestResults(); | ||
} | ||
|
||
private bool TryExecuteITestDataSource(List<TestResult> results) | ||
{ | ||
if (_test.DataType != DynamicDataType.ITestDataSource) | ||
{ | ||
return false; | ||
} | ||
|
||
UTF.ITestDataSource? dataSource; | ||
object?[]? data; | ||
if (_test.SerializedData?.Length == 3 | ||
&& Enum.TryParse(_test.SerializedData[0], out TestDataIdentifierStrategy _)) | ||
{ | ||
if (!int.TryParse(_test.SerializedData[1], out int dataSourceIndex) | ||
|| !int.TryParse(_test.SerializedData[2], out int dataIndex)) | ||
{ | ||
// TODO | ||
throw new InvalidOperationException(); | ||
Evangelink marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
dataSource = _testMethodInfo.GetAttributes<Attribute>(false)?.OfType<UTF.ITestDataSource>().Skip(dataSourceIndex).FirstOrDefault(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may be a good idea to check with runtime team that it's safe to assume reflection will return attributes in a deterministic order. I think it should be a safe assumption, but just a sanity check. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From my tests it is deterministic but yes I'll double check with them. |
||
if (dataSource is null) | ||
{ | ||
// TODO | ||
throw new InvalidOperationException(); | ||
Evangelink marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
data = dataSource.GetData(_testMethodInfo.MethodInfo).Skip(dataIndex).FirstOrDefault(); | ||
} | ||
else | ||
{ | ||
dataSource = null; | ||
data = DataSerializationHelper.Deserialize(_test.SerializedData); | ||
} | ||
|
||
TestResult[] testResults = ExecuteTestWithDataSource(dataSource, data); | ||
results.AddRange(testResults); | ||
|
||
return true; | ||
} | ||
|
||
private bool TryExecuteDataSourceBasedTests(List<TestResult> results) | ||
{ | ||
DataSourceAttribute[] dataSourceAttribute = _testMethodInfo.GetAttributes<DataSourceAttribute>(false); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
namespace Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
||
/// <summary> | ||
/// Defines the strategy for uniquely identifying test data. | ||
/// This is only used when <see cref="ITestDataSourceUnfoldingCapability.UnfoldingStrategy" /> is set to <see cref="TestDataSourceUnfoldingStrategy.Unfold"/>. | ||
/// </summary> | ||
public interface ITestDataIdentifierStrategy | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given this enum and interface only work when using the unfolding strategy, I was wondering if we should merge the 2 together so we have something like WDYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Evangelink You mean not needing the interface at all, and only relying on the existing enum? This is fine for me. We will have to keep There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes that's what I meant. My last commit is doing the change, please review and let me know if you think that's better or worse. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks better to me |
||
{ | ||
/// <summary> | ||
/// Gets the strategy used to uniquely identify test data. | ||
/// </summary> | ||
TestDataIdentifierStrategy IdentifierStrategy { get; } | ||
} | ||
|
||
/// <summary> | ||
/// Specifies the available strategies for identifying test data. | ||
/// This is only relevant when <see cref="ITestDataSourceUnfoldingCapability.UnfoldingStrategy" /> is set to <see cref="TestDataSourceUnfoldingStrategy.Unfold"/>. | ||
/// </summary> | ||
public enum TestDataIdentifierStrategy : byte | ||
{ | ||
/// <summary> | ||
/// Automatically determines the identifier strategy based on the assembly-level attribute | ||
/// <see cref="TestDataSourceOptionsAttribute" />. If no attribute is specified, the default is | ||
/// <see cref="DataContractSerialization" />. | ||
/// </summary> | ||
Auto, | ||
|
||
/// <summary> | ||
/// Identifies test data using data contract serialization. | ||
/// </summary> | ||
DataContractSerialization, | ||
|
||
/// <summary> | ||
/// Identifies test data by its index in the data source. | ||
/// </summary> | ||
DataIndex, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the context of HotReload, if an attribute is removed, re-ordered, etc, is everything going to work fine? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will double check that scenario! |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am reusing the serialized data property as it's not used and allows me to avoid adding more properties to the TestCase object as it has some perf impact. This isn't perfect but as far as I can tell, there is no way for the serialized data to be serialized this way as we prefix with the data type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine for me to reuse. At least until we have a strong reason not to reuse.