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

Offer alternative to serialization of data #4467

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

Evangelink
Copy link
Member

@Evangelink Evangelink commented Dec 29, 2024

This pull request includes significant changes to the MSTest.TestAdapter and TestFramework to introduce a new strategy for identifying test data in data-driven tests. The changes involve updating the test discovery and execution logic to support the new TestDataIdentifierStrategy.

Fixes #1462

IMPORTANT: when using the data index strategy any impact on the order of the data will impact the index which in turn will impact the test ID. This can have important side effect if you are using a system tracking the test ID over time.

Key changes include:

Enhancements to Test Discovery:

  • Modified the EnumerateAssembly method in AssemblyEnumerator.cs to include the new TestDataIdentifierStrategy when discovering tests. [1] [2] [3]
  • Updated the DiscoverTestsInType method to pass the TestDataIdentifierStrategy to the test discovery process. [1] [2]

Enhancements to Test Execution:

  • Added a new method TryExecuteITestDataSource in TestMethodRunner.cs to handle the execution of tests using the new identifier strategy. [1] [2]

Interface and Attribute Updates:

  • Introduced the ITestDataIdentifierStrategy interface and the TestDataIdentifierStrategy enum to define the strategy for uniquely identifying test data.
  • Updated the DataRowAttribute and DynamicDataAttribute to implement the new ITestDataIdentifierStrategy interface. [1] [2] [3] [4]
  • Enhanced the TestDataSourceOptionsAttribute to include the new identifier strategy.

TODOs:

  • Add tests
  • Add documentation
  • Finish todo exceptions (or failed state?)
  • Better explain consequences on test ID
  • Better explain impact when ordering changes

/// 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
Copy link
Member Author

Choose a reason for hiding this comment

The 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 Auto, Fold, UnfoldUsingDataContractSerialization, UnfoldUsingDataIndex.

WDYT?

Copy link
Member

Choose a reason for hiding this comment

The 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 Unfold and make it the same as UnfoldUsingDataContractSerialization for backcompat I assume. But that's fine.

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

Copy link
Member

Choose a reason for hiding this comment

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

Looks better to me

{
discoveredTest.TestMethod.SerializedData = DataSerializationHelper.Serialize(d);
discoveredTest.TestMethod.SerializedData = new string[3]
Copy link
Member Author

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.

Copy link
Member

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.

throw new InvalidOperationException();
}

dataSource = _testMethodInfo.GetAttributes<Attribute>(false)?.OfType<UTF.ITestDataSource>().Skip(dataSourceIndex).FirstOrDefault();
Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

/// <summary>
/// Identifies test data by its index in the data source.
/// </summary>
DataIndex,
Copy link
Member

Choose a reason for hiding this comment

The 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?

Copy link
Member Author

Choose a reason for hiding this comment

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

Will double check that scenario!

Comment on lines +264 to +265
|| !int.TryParse(_test.SerializedData[1], out int dataSourceIndex)
|| !int.TryParse(_test.SerializedData[2], out int dataIndex))
Copy link
Member

Choose a reason for hiding this comment

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

Consider using the IFormatProvider overload and pass CultureInfo.InvariantCulture.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm surprised there was no CA warning here. I need to verify the existing rules.

/// Each data row is treated as a separate test case, and the data is unfolded using
/// <see cref="System.Runtime.Serialization.Json.DataContractJsonSerializer"/>.
/// </summary>
UnfoldUsingDataContractJsonSerializer,
Copy link
Member

Choose a reason for hiding this comment

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

Should we make this the same numeric value as Unfold?

/// </summary>
Auto,

/// <summary>
/// Each data row is treated as a separate test case.
/// </summary>
[Obsolete("Use 'UnfoldUsingDataContractJsonSerializer' instead")]
Copy link
Member

Choose a reason for hiding this comment

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

Consider EditorBrowsable(Never), and maybe also inheritdoc from UnfoldUsingDataContractJsonSerializer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use a better serialization/deserialization mechanism for data discovery
2 participants