C# 是否有更好的方法将动态输入在线传递给DataTestMethod?即,如何以编程方式为数据驱动测试创建测试输入

C# 是否有更好的方法将动态输入在线传递给DataTestMethod?即,如何以编程方式为数据驱动测试创建测试输入,c#,.net-core,mstest,data-driven-tests,C#,.net Core,Mstest,Data Driven Tests,我多年来一直在寻找这一点,我想我终于在“MSTest V2”中找到了一种真正的方法(意思是.netcore附带的方法,并且只有在Visual Studio 2017中才能真正正确处理)。请参阅我的答案以了解我的解决方案 这为我解决的问题是,我的输入数据不容易序列化,但我的逻辑需要使用许多这些输入进行测试。有很多原因可以解释为什么这样做更好,但这对我来说是个阻碍;我被迫进行一个巨大的单元测试,其中一个for循环通过我的输入。到目前为止。因此新的DataTestMethodAttribute类是可重

我多年来一直在寻找这一点,我想我终于在“MSTest V2”中找到了一种真正的方法(意思是.netcore附带的方法,并且只有在Visual Studio 2017中才能真正正确处理)。请参阅我的答案以了解我的解决方案


这为我解决的问题是,我的输入数据不容易序列化,但我的逻辑需要使用许多这些输入进行测试。有很多原因可以解释为什么这样做更好,但这对我来说是个阻碍;我被迫进行一个巨大的单元测试,其中一个for循环通过我的输入。到目前为止。

因此新的DataTestMethodAttribute类是可重写的,它允许使用此签名重写方法:

public override TestResult[] Execute(ITestMethod testMethod);
一旦我发现了这一点,就很容易了:我只是推导、计算输入,然后在Execute方法中循环使用它们。不过,为了使其易于重用,我又向前走了几步

因此,首先是一个重写该Execute方法的基类,并公开一个返回IEnumerable的抽象GetTestInputs()方法。您可以从中派生任何可以实现该方法的类型

public abstract class DataTestMethodWithProgrammaticTestInputs : DataTestMethodAttribute
{
    protected Lazy<IEnumerable> _items;

    public DataTestMethodWithProgrammaticTestInputs()
    {
        _items = new Lazy<IEnumerable>(GetTestInputs, true);
    }

    protected abstract IEnumerable GetTestInputs();

    public override TestResult[] Execute(ITestMethod testMethod)
    {
        var results = new List<TestResult>();
        foreach (var testInput in _items.Value)
        {
            var result = testMethod.Invoke(new object[] { testInput });
            var overriddenDisplayName = GetDisplayNameForTestItem(testInput);
            if (!string.IsNullOrEmpty(overriddenDisplayName))
                result.DisplayName = overriddenDisplayName;
            results.Add(result);
        }
        return results.ToArray();
    }

    public virtual string GetDisplayNameForTestItem(object testItem)
    {
        return null;
    }
}
最后,这里是一个使用中的派生属性类型的示例,可以轻松地用于许多测试:

[TestClass]
public class MyTestClass
{
    public class MyTestInputType{public string Key; public Func<string> F; }
    public IEnumerable TestInputs 
    {
        get
        {
            return new MyTestInputType[] 
            { 
                new MyTestInputType(){ Key = "1", F = () => "" }, 
                new MyTestInputType() { Key = "2", F = () => "2" } 
            };
        }
    }

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class DataTestMethodWithTestInputsFromThisTestProjectAttribute : DataTestMethodWithTestInputsFromClassPropertyAttribute
    {
        public DataTestMethodWithTestInputsFromThisTestProjectAttribute() 
            : base(typeof(MyTestClass), nameof(MyTestClass.TestInputs)) { }

        public override string GetDisplayNameForTestItem(object testItem)
        {
            var asTestInput = testItem as MyTestInputType;
            if (asTestInput == null)
                return null;
            return asTestInput.Key;
        }
    }

    [DataTestMethodWithTestInputsFromThisTestProject]
    public void TestMethod1(MyTestInputType testInput)
    {
         Assert.IsTrue(testInput.Key == testInput.F());
    }

    [DataTestMethodWithTestInputsFromThisTestProject]
    public void TestMethod2(MyTestInputType testInput)
    {
        Assert.IsTrue(string.IsNullOrEmpty(testInput.F()));
    }
}
[TestClass]
公共类MyTestClass
{
公共类MyTestInputType{public string Key;public Func F;}
公共IEnumerable测试输入
{
得到
{
返回新的MyTestInputType[]
{ 
新的MyTestInputType(){Key=“1”,F=()=>“”},
新的MyTestInputType(){Key=“2”,F=()=>“2”}
};
}
}
[AttributeUsage(AttributeTargets.Method,AllowMultiple=false)]
公共类DataTestMethodWithTestInputsFromThisTestProjectAttribute:DataTestMethodWithTestInputsFromClassPropertyAttribute
{
公共DataTestMethodWithTestInputsFromThisTestProjectAttribute()
:base(typeof(MyTestClass),nameof(MyTestClass.TestInputs)){}
公共重写字符串GetDisplayNameForTestItem(对象testItem)
{
var asTestInput=testItem作为MyTestInputType;
如果(asTestInput==null)
返回null;
返回put.Key;
}
}
[DataTestMethodWithTestInputsFromThisTestProject]
公共void TestMethod1(MyTestInputType testInput)
{
Assert.IsTrue(testInput.Key==testInput.F());
}
[DataTestMethodWithTestInputsFromThisTestProject]
公共void TestMethod2(MyTestInputType testInput)
{
Assert.IsTrue(string.IsNullOrEmpty(testInput.F());
}
}

就这样。有人有更好的mstest方法吗?

您现在可以使用DynamicDataAttribute:

[DynamicData(nameof("TestMethodInput"))]
[DataTestMethod]
public void TestMethod(List<string> list)
{
    Assert.AreEqual(2, list.Count);
}

public static IEnumerable<object[]> TestMethodInput
{
    get
    {
        return new[]
        {
            new object[] { new List<string> { "one" } },
            new object[] { new List<string> { "one", "two" } },
            new object[] { new List<string> { "one", "two", "three" } }
        };
    }
}
[dynamicata(nameof(“TestMethodInput”))]
[数据测试方法]
公共void测试方法(列表)
{
Assert.AreEqual(2,list.Count);
}
公共静态IEnumerable TestMethodInput
{
得到
{
返回新的[]
{
新对象[]{新列表{“一”},
新对象[]{新列表{“一”,“二”},
新对象[]{新列表{“一”、“二”、“三”}
};
}
}
对at有一个很好的缺点


中有更多血淋淋的细节,看起来确实简单得多。但是我找不到任何关于DynamicDataAttribute或DynamicCDATA的文档@ovolo你能提供链接吗?我只找到了以下链接:我为documentationBrilliant添加了一些链接!虽然似乎不应该有引号:
[DynamicData(nameof(TestMethodInput))]
在动态数据方法(或属性)中将返回值定义为IEnumerable很重要。它不适用于返回的不同类型。
[DynamicData(nameof("TestMethodInput"))]
[DataTestMethod]
public void TestMethod(List<string> list)
{
    Assert.AreEqual(2, list.Count);
}

public static IEnumerable<object[]> TestMethodInput
{
    get
    {
        return new[]
        {
            new object[] { new List<string> { "one" } },
            new object[] { new List<string> { "one", "two" } },
            new object[] { new List<string> { "one", "two", "three" } }
        };
    }
}