gpt4 book ai didi

c# - 使用泛型的 xUnit 理论测试

转载 作者:可可西里 更新时间:2023-11-01 08:25:48 28 4
gpt4 key购买 nike

在 xUnit 中,我可以有一个使用这种形式的泛型的 Theory 测试:

[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 };
}

这将给我通用 T 参数作为 double。是否可以使用 MemberData 为具有如下签名的测试指定泛型类型参数:

[Theory]
[MemberData(SomeTypeScenario)]
public void TestMethod<T>()
{
Assert.Equal(typeof(double), typeof(T));
}

如果不能使用 MemberData 或任何其他提供的属性(我怀疑它不是),是否可以为 Xunit 创建一个可以实现此目的的属性?也许类似于在 Scenarios 方法中指定类型并以与 Jon Skeet 在这里的回答类似的方式使用反射:Generics in C#, using type of a variable as parameter

最佳答案

您可以简单地将 Type 作为输入参数包含在内。例如:

[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 上使用泛型。

编辑(如果你真的需要泛型)

1) 你需要子类化 ITestMethod 来保存泛型方法信息,它还必须实现 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

的子类
// 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 属性将其挂接到您的自定义发现器

// 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));
}

关于c# - 使用泛型的 xUnit 理论测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39570641/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com