xUnit theory test using generics(使用泛型的 xUnit 理论测试)
问题描述
在 xUnit 中,我可以有一个 Theory 测试,它以这种形式使用泛型:
In xUnit I can have a Theory test that uses generics in this form:
[Theory]
[MemberData(SomeScenario)]
public void TestMethod<T>(T myType)
{
Assert.Equal(typeof(double), typeof(T));
}
public static IEnumerable<object[]> SomeScenario()
{
yield return new object[] { 1.23D };
}
这会给我作为 double 的通用 T 参数.是否可以使用 MemberData 为具有如下签名的测试指定泛型类型参数:
Which will give me the generic T parameter as double. Is it possible to use MemberData to specify the generic type parameter for a test with a signature like:
[Theory]
[MemberData(SomeTypeScenario)]
public void TestMethod<T>()
{
Assert.Equal(typeof(double), typeof(T));
}
如果 MemberData 或任何其他提供的属性(我怀疑它不是)不可能,是否可以为 Xunit 创建一个可以实现此目的的属性?也许类似于在场景方法中指定类型并以类似于 Jon Skeet 在此处的回答的方式使用反射:Generics in C#, using变量的类型作为参数
If it is not possible with MemberData or any other provided attribute (which I'm suspecting that it isn't), is it possible to create an attribute for Xunit that can achieve this? Maybe something along the lines of specifying Types in the Scenarios method and using reflection in a similar manner to Jon Skeet's answer here: Generics in C#, using type of a variable as parameter
推荐答案
您可以简单地包含 Type 作为输入参数.例如:
You can simply include Type as an input parameter instead. E.g.:
[Theory]
[MemberData(SomeTypeScenario)]
public void TestMethod(Type type) {
Assert.Equal(typeof(double), type);
}
public static IEnumerable<object[]> SomeScenario() {
yield return new object[] { typeof(double) };
}
在 xunit 上没有必要使用泛型.
There is no need to go with generics on xunit.
编辑(如果你真的需要泛型)
1) 你需要继承 ITestMethod 来保存泛型方法信息,它还必须实现 IXunitSerializable
1) You need to subclass ITestMethod to persist generic method info, it also has to implement IXunitSerializable
// assuming namespace Contosco
public class GenericTestMethod : MarshalByRefObject, ITestMethod, IXunitSerializable
{
public IMethodInfo Method { get; set; }
public ITestClass TestClass { get; set; }
public ITypeInfo GenericArgument { get; set; }
/// <summary />
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public GenericTestMethod()
{
}
public GenericTestMethod(ITestClass @class, IMethodInfo method, ITypeInfo genericArgument)
{
this.Method = method;
this.TestClass = @class;
this.GenericArgument = genericArgument;
}
public void Serialize(IXunitSerializationInfo info)
{
info.AddValue("MethodName", (object) this.Method.Name, (Type) null);
info.AddValue("TestClass", (object) this.TestClass, (Type) null);
info.AddValue("GenericArgumentAssemblyName", GenericArgument.Assembly.Name);
info.AddValue("GenericArgumentTypeName", GenericArgument.Name);
}
public static Type GetType(string assemblyName, string typeName)
{
#if XUNIT_FRAMEWORK // This behavior is only for v2, and only done on the remote app domain side
if (assemblyName.EndsWith(ExecutionHelper.SubstitutionToken, StringComparison.OrdinalIgnoreCase))
assemblyName = assemblyName.Substring(0, assemblyName.Length - ExecutionHelper.SubstitutionToken.Length + 1) + ExecutionHelper.PlatformSuffix;
#endif
#if NET35 || NET452
// Support both long name ("assembly, version=x.x.x.x, etc.") and short name ("assembly")
var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == assemblyName || a.GetName().Name == assemblyName);
if (assembly == null)
{
try
{
assembly = Assembly.Load(assemblyName);
}
catch { }
}
#else
System.Reflection.Assembly assembly = null;
try
{
// Make sure we only use the short form
var an = new AssemblyName(assemblyName);
assembly = System.Reflection.Assembly.Load(new AssemblyName { Name = an.Name, Version = an.Version });
}
catch { }
#endif
if (assembly == null)
return null;
return assembly.GetType(typeName);
}
public void Deserialize(IXunitSerializationInfo info)
{
this.TestClass = info.GetValue<ITestClass>("TestClass");
string assemblyName = info.GetValue<string>("GenericArgumentAssemblyName");
string typeName = info.GetValue<string>("GenericArgumentTypeName");
this.GenericArgument = Reflector.Wrap(GetType(assemblyName, typeName));
this.Method = this.TestClass.Class.GetMethod(info.GetValue<string>("MethodName"), true).MakeGenericMethod(GenericArgument);
}
}
2) 您需要为泛型方法编写自己的发现器,它必须是 IXunitTestCaseDiscoverer
2) You need to write your own discoverer for generic methods, it has to be subclass of IXunitTestCaseDiscoverer
// assuming namespace Contosco
public class GenericMethodDiscoverer : IXunitTestCaseDiscoverer
{
public GenericMethodDiscoverer(IMessageSink diagnosticMessageSink)
{
DiagnosticMessageSink = diagnosticMessageSink;
}
protected IMessageSink DiagnosticMessageSink { get; }
public IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions,
ITestMethod testMethod, IAttributeInfo factAttribute)
{
var result = new List<IXunitTestCase>();
var types = factAttribute.GetNamedArgument<Type[]>("Types");
foreach (var type in types)
{
var typeInfo = new ReflectionTypeInfo(type);
var genericMethodInfo = testMethod.Method.MakeGenericMethod(typeInfo);
var genericTestMethod = new GenericTestMethod(testMethod.TestClass, genericMethodInfo, typeInfo);
result.Add(
new XunitTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(),
genericTestMethod));
}
return result;
}
}
3) 最后,您可以为泛型方法创建属性,并通过 XunitTestCaseDiscoverer 属性将其挂钩到您的自定义发现器
3) Finally you can make your attribute for generic methods and hook it to your custom discoverer by XunitTestCaseDiscoverer attribute
// assuming namespace Contosco
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer("Contosco.GenericMethodDiscoverer", "Contosco")]
public sealed class GenericMethodAttribute : FactAttribute
{
public Type[] Types { get; private set; }
public GenericMethodAttribute(Type[] types)
{
Types = types;
}
}
用法:
[GenericMethod(new Type[] { typeof(double), typeof(int) })]
public void TestGeneric<T>()
{
Assert.Equal(typeof(T), typeof(double));
}
这篇关于使用泛型的 xUnit 理论测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用泛型的 xUnit 理论测试
基础教程推荐
- 从 C# 控制相机设备 2022-01-01
- 如果条件可以为空 2022-01-01
- 重新排序 WPF TabControl 中的选项卡 2022-01-01
- 将数据集转换为列表 2022-01-01
- Mono https webrequest 失败并显示“身份验证或解密失败" 2022-01-01
- C# 9 新特性——record的相关总结 2023-04-03
- 更新 Visual Studio 中的 DataSet 结构以匹配新的 SQL 数据库结构 2022-01-01
- 获取C#保存对话框的文件路径 2022-01-01
- SonarQube C# 分析失败“不是指针的有效行偏移" 2022-01-01
- 在 VB6 或经典 ASP 中使用 .NET 2022-01-01
