Add support for 'TypeConverters' in argument matching for DataRowTests
See original GitHub issueDescription
Currently, the argument matching between the constants specified in the DataRow
attribute and the corresponding method parameters appears to be done using basic reflection plus direct argument passing without any processing. This ends up enforcing exact matches on types most of the time. Due to this, advanced scenarios like converting string
s to Type
objects or Uri
instances for example are not supported.
Adding support for the TypeConverter
-based system during the matching phase would allow richer scenarios without having to fallback to using [DynamicData()]
which leads to more complex code overall.
Creating TypeConverter
classes is a very common and widely used mechanism to allow conversions between arbitrary types, so supporting them wouldn’t create coupling in the test framework to anything non-standard.
For more information on the TypeConverter
and TypeDescriptor
system, here is the main page:
Notice from the inheritance tree how much converters are used. A few very useful ones that could be leveraged for testing:
- System.UriTypeConverter
- System.ComponentModel.DateTimeConverter
- System.ComponentModel.DateTimeOffsetConverter
- System.ComponentModel.EnumConverter
- System.ComponentModel.GuidConverter
- System.ComponentModel.TimeSpanConverter
Keep in mind that to support these there is no need to create custom implementations for each one: just fetching the TypeDescriptor
for an object generically will already ensure the default TypeConverter
is used for that type.
Steps to reproduce
This is what I’m proposing:
[DataTestMethod]
[DataRow("http://www.google.com")]
[DataRow("http://www.github.com")]
public void MyTest(Uri url)
{
...
}
Expected behavior
The strings passed in the DataRow
attribute should be converted into the parameters in the method respecting the specified TypeConverter
applied on the parameter type.
Because the Uri
type already references the UriTypeConverter
via an attribute (from referencesource, this would work automatically without having to specify any converter on the argument itself:
[Serializable]
[TypeConverter(typeof(UriTypeConverter))]
public partial class Uri : ISerializable {
Actual behavior
An exception is thrown:
Result1 StackTrace: at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast) at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig) at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
Environment
- MSTest.TestAdapter 1.2.0
- MSTest.TestFramework 1.2.0
Issue Analytics
- State:
- Created 5 years ago
- Reactions:2
- Comments:9 (6 by maintainers)
Top GitHub Comments
Hi @julealgon, currently the
DynamicData
attribute is the only way to achieve this. This is a completely valid ask hence marking this issue asup-for-grabs
andenhancement
. You can raise a PR for the same and we’ll be happy to take a look.Fully aligned with you on that. If it wouldn’t be for the Test Explorer view, I would not use
DynamicData
and do a local loop.That’s interesting indeed. I didn’t get what you were suggesting correctly it seems. Maybe I am getting biased by my personal view but I usually don’t like magic conversion and prefer to be in control of what I am doing.
If we go for such design, we should probably do the same with data coming from other sources to offer consistent behavior.
At the moment we don’t get much traction from community so it’s hard to do the right balance calls. I will keep this closed for the time being and will reconsider suggesting it when/if we manage to get more people contributing ideas/feelings about this tool.
Thank you so much for the valuable time and feedback @julealgon!