如何在MSTest中运行具有多个参数的测试方法?


140

NUnit具有一个称为“值”的功能,如下所示:

[Test]
public void MyTest(
    [Values(1,2,3)] int x,
    [Values("A","B")] string s)
{
    // ...
}

这意味着测试方法将运行6次:

MyTest(1, "A")
MyTest(1, "B")
MyTest(2, "A")
MyTest(2, "B")
MyTest(3, "A")
MyTest(3, "B")

我们现在正在使用MSTest,是否有与此等效的功能,以便可以使用多个参数运行相同的测试?

[TestMethod]
public void Mytest()
{
    // ...
}

您可以使用MSTestHacks,如stackoverflow.com/a/19536942/52277答案中所述。
Michael Freidgeim


@MichaelFreidgeim这个问题比您建议的目标有更好的答案
Rob

1
@Rob:恕我直言,最合适的答案-MSTestHacks- 如何使用MSTest进行RowTest?这个问题中缺少。
Michael Freidgeim

@MichaelFreidgeim也许,但似乎功能已经存在了,现在3年半(stackoverflow.com/questions/9021881/...
罗布

Answers:


46

不幸的是,MSTest不支持它。显然有一个可扩展性模型,您可以自己实现。另一种选择是使用数据驱动的测试

我个人的看法是,尽管坚持使用NUnit ...

编辑:从Visual Studio 2012更新1开始,MSTest具有类似的功能。请参阅下面的@McAden的答案


我们正在使用Selenium生成NUnit代码,所以我们改用NUnit :)
The Light

4
我发现在Visual Studio 2012 Update 1中现在可以实现类似的功能,仅供参考,供以后考虑此答案的任何人参考。
McAden 2012年

@McAden您是否具有说明链接?
jeroenh 2012年

6
我在下面给出了答案,并提供了示例和指向我的博客文章的链接。它提到了必要的属性,并在该属性中提到了“ DisplayName”属性,以区分测试浏览器中的情况。也有人在CTP(现在已经正式发布)的月announcment提到blogs.msdn.com/b/visualstudioalm/archive/2012/10/26/...我添加的信息,这太问题,因为我花了很多时间寻找它。希望这可以节省一些时间。
McAden 2012年

167

编辑4:看起来这已在2016年6月17日在MSTest V2中完成:https ://blogs.msdn.microsoft.com/visualstudioalm/2016/06/17/taking-the-mstest-framework-forward-with-mstest- v2 /

原始答案

大约在一周前,在Visual Studio 2012 Update 1中,现在可以实现类似的功能:

[DataTestMethod]
[DataRow(12,3,4)]
[DataRow(12,2,6)]
[DataRow(12,4,3)]
public void DivideTest(int n, int d, int q)
{
  Assert.AreEqual( q, n / d );
}

编辑:看来这仅在WinRT / Metro的单元测试项目中可用。布默

编辑2:以下是在Visual Studio中使用“转到定义”找到的元数据:

#region Assembly Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll, v11.0.0.0
// C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\MSTestFramework\11.0\References\CommonConfiguration\neutral\Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll
#endregion

using System;

namespace Microsoft.VisualStudio.TestPlatform.UnitTestFramework
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class DataTestMethodAttribute : TestMethodAttribute
    {
        public DataTestMethodAttribute();

        public override TestResult[] Execute(ITestMethod testMethod);
    }
}

编辑3:此问题是在Visual Studio的UserVoice论坛中提出的。最近更新状态:

已开始·Visual Studio团队ADMIN Visual Studio团队(Microsoft Visual Studio产品团队)做出了回应·2016年4月25日,谢谢您的反馈。我们已经开始对此进行研究。

Pratap Lakshman Visual Studio

https://visualstudio.uservoice.com/forums/330519-team-services/suggestions/3865310-allow-use-of-datatestmethod-datarow-in-all-unit


4
现在支持的Windows Phone也使用Visual Studio 2012更新2(目前,CTP 4)
佩德罗喇嘛

8
我有更新1,但无法识别DataTestMethod和DataRow,这些属性在哪个库中?
DevDave

3
是否有有关DataTestMethod的官方资料?它在哪个名称空间中,在哪个程序集中?
伊戈尔·兰金

2
我发现UnitTestFramework.dll已安装在我的计算机上,在手动引用它之后,我可以使用带有数据行的[DataTestMethod]属性编写方法,但无法在Visual Studio 2012.3中获取测试资源管理器来找到该方法。
2013年

5
我在计算机上转到了文件路径“ C:\ Program Files(x86)\ Microsoft SDKs \ Windows \ v8.0 \ ExtensionSDKs \ MSTestFramework \ 11.0 \ References \ CommonConfiguration \ neutral \ Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll”文件在那里。所以我在基本单元测试项目中引用了它。在JustDecompile中打开dll表示该库仅具有对mscorlib,System和System.Core的引用。这不是Windows Store项目。
乔什·德隆

34

此功能现已在预发行版本中,可与VS 2015一起使用。

例如:

[TestClass]
public class UnitTest1
{
    [DataTestMethod]
    [DataRow(1, 2, 2)]
    [DataRow(2, 3, 5)]
    [DataRow(3, 5, 8)]
    public void AdditionTest(int a, int b, int result)
    {
        Assert.AreEqual(result, a + b);
    }
}

这是正确的答案。请注意,不必说[DataTestMethod]即可使用[DataRow](stackoverflow.com/a/59162403/2540235
mattavatar

11

由于没有人提到-与NUnit的Value(或TestCase)属性不完全相同,但是MSTest具有DataSource属性,它使您可以执行类似的操作。您可以将其连接到数据库或XML文件-不像NUnit的功能那么简单,但是可以完成。



6

实现非常简单-您应该使用TestContextproperty和TestPropertyAttribute

public TestContext TestContext { get; set; }
private List<string> GetProperties()
{
    return TestContext.Properties
        .Cast<KeyValuePair<string, object>>()
        .Where(_ => _.Key.StartsWith("par"))
        .Select(_ => _.Value as string)
        .ToList();
}

//usage
[TestMethod]
[TestProperty("par1", "http://getbootstrap.com/components/")]
[TestProperty("par2", "http://www.wsj.com/europe")]
public void SomeTest()
{
    var pars = GetProperties();
    //...
}

编辑:

我准备了一些扩展方法来简化对TestContext属性的访问,并像我们有几个测试用例一样工作。请参阅此处处理简单测试属性的示例:

[TestMethod]
[TestProperty("fileName1", @".\test_file1")]
[TestProperty("fileName2", @".\test_file2")]
[TestProperty("fileName3", @".\test_file3")]
public void TestMethod3()
{
    TestContext.GetMany<string>("fileName").ForEach(fileName =>
    {
        //Arrange
        var f = new FileInfo(fileName);

        //Act
        var isExists = f.Exists;

        //Asssert
        Assert.IsFalse(isExists);
    });
}

以及创建复杂测试对象的示例:

[TestMethod]
//Case 1
[TestProperty(nameof(FileDescriptor.FileVersionId), "673C9C2D-A29E-4ACC-90D4-67C52FBA84E4")]
//...
public void TestMethod2()
{
    //Arrange
    TestContext.For<FileDescriptor>().Fill(fi => fi.FileVersionId).Fill(fi => fi.Extension).Fill(fi => fi.Name).Fill(fi => fi.CreatedOn, new CultureInfo("en-US", false)).Fill(fi => fi.AccessPolicy)
        .ForEach(fileInfo =>
        {
            //Act
            var fileInfoString = fileInfo.ToString();

            //Assert
            Assert.AreEqual($"Id: {fileInfo.FileVersionId}; Ext: {fileInfo.Extension}; Name: {fileInfo.Name}; Created: {fileInfo.CreatedOn}; AccessPolicy: {fileInfo.AccessPolicy};", fileInfoString);
        });
}

查看扩展方法样本集以获取更多详细信息。


2
这种方法有效,但不会为每个参数集创建单独的测试用例。
usr4896260

您可以使用更复杂的值作为TestProperty值(例如“ 0-100”),在测试正文中进行解析和处理。
安德烈·伯瑞金

4

当然,还有另一种方法可以做到这一点,而在本线程中尚未讨论过,即通过继承包含TestMethod的类。在下面的示例中,仅定义了一个TestMethod,但创建了两个测试用例。

在Visual Studio 2012中,它在TestExplorer中创建两个测试:

  1. DemoTest_B10_A5.test
  2. DemoTest_A12_B4.test

    public class Demo
    {
        int a, b;
    
        public Demo(int _a, int _b)
        {
            this.a = _a;
            this.b = _b;
        }
    
        public int Sum()
        {
            return this.a + this.b;
        }
    }
    
    public abstract class DemoTestBase
    {
        Demo objUnderTest;
        int expectedSum;
    
        public DemoTestBase(int _a, int _b, int _expectedSum)
        {
            objUnderTest = new Demo(_a, _b);
            this.expectedSum = _expectedSum;
        }
    
        [TestMethod]
        public void test()
        {
            Assert.AreEqual(this.expectedSum, this.objUnderTest.Sum());
        }
    }
    
    [TestClass]
    public class DemoTest_A12_B4 : DemoTestBase
    {
        public DemoTest_A12_B4() : base(12, 4, 16) { }
    }
    
    public abstract class DemoTest_B10_Base : DemoTestBase
    {
        public DemoTest_B10_Base(int _a) : base(_a, 10, _a + 10) { }
    }
    
    [TestClass]
    public class DemoTest_B10_A5 : DemoTest_B10_Base
    {
        public DemoTest_B10_A5() : base(5) { }
    }


3

我无法让The DataRowAttribute在Visual Studio 2015中工作,这是我最终得到的结果:

[TestClass]
public class Tests
{
    private Foo _toTest;

    [TestInitialize]
    public void Setup()
    {
        this._toTest = new Foo();       
    }

    [TestMethod]
    public void ATest()
    {
        this.Perform_ATest(1, 1, 2);
        this.Setup();

        this.Perform_ATest(100, 200, 300);
        this.Setup();

        this.Perform_ATest(817001, 212, 817213);
        this.Setup();

    }

    private void Perform_ATest(int a, int b, int expected)
    {
        //Obviously this would be way more complex...

        Assert.IsTrue(this._toTest.Add(a,b) == expected);    
    }
}

public class Foo
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

真正的解决方案是仅使用NUnit(除非您像我在此特定实例中那样陷入MSTest)。


3
您应将每个测试调用拆分为一个单独的测试,以节省您其中一个中断的时间。(我们都知道会发生)

当然是。在实践中就是这样做的。在这种情况下,我只是为了简单起见进行了说明
Brandon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.