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

Posted

技术标签:

【中文标题】我们如何在 MSTest 中运行具有多个参数的测试方法?【英文标题】:How can we run a test method with multiple parameters in MSTest? 【发布时间】:2012-02-19 18:26:41 【问题描述】:

NUnit 有一个名为 Values 的功能,如下所示:

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

    // ...

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

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

我们现在正在使用 MSTest,但是有没有任何等效的方法可以让我使用多个参数运行相同的测试?

[TestMethod]
public void Mytest()

    // ...

【问题讨论】:

您可以使用 MSTestHacks,如***.com/a/19536942/52277 回答中所述。 How to RowTest with MSTest?的可能重复 @MichaelFreidgeim 这个问题的答案比你建议的目标好 @Rob:恕我直言,这个问题中缺少最合适的答案 -MSTestHacks -How to RowTest with MSTest?。 @MichaelFreidgeim 也许,尽管该功能似乎已经存在了 3 1/2 年 (***.com/questions/9021881/…) 【参考方案1】:

MSTest 不支持该功能,但您可以实现自己的属性来实现该功能。

看看Enabling parameterized tests in MSTest using PostSharp

【讨论】:

【参考方案2】:

很遗憾,旧版本的 MSTest 不支持它。显然有一个extensibility model and you can implement it yourself。另一种选择是使用data-driven tests。

我个人的意见是坚持使用 NUnit...

从 Visual Studio 2012 更新 1 开始,MSTest 具有类似的功能。见McAden's answer。

【讨论】:

我们使用 Selenium 生成 NUnit 代码,所以我们改用 NUnit :) 我发现在 Visual Studio 2012 Update 1 中现在可以进行类似的操作,仅供参考,以供将来查看此答案的任何人考虑。 @McAden 你有解释的链接吗? 我在下面给出了答案,并附有一个示例和指向我的博客文章的链接。它提到了必要的属性以及用于区分测试资源管理器中的案例的属性上的“DisplayName”属性。在 CTP 的 10 月公告(现已正式发布)blogs.msdn.com/b/visualstudioalm/archive/2012/10/26/… 中也提到了这一点,我已将信息添加到此 SO 问题中,因为我花了很多时间寻找它。希望这可以节省一些时间。【参考方案3】:

与 NUnit 的 Value(或 TestCase)属性不完全相同,但 MSTest 具有 DataSource 属性,它允许您做类似的事情。

您可以将它连接到数据库或 XML 文件 - 它不像 NUnit 的功能那么简单,但它可以完成这项工作。

【讨论】:

【参考方案4】:

MSTest 有一个名为DataSource 的强大属性。使用它,您可以按照您的要求执行数据驱动的测试。您可以将测试数据保存在 XML、CSV 或数据库中。这里有几个链接可以指导您

Unit Testing with VSTS 2008 (Part 3) How To: Create a Data-Driven Unit Test Walkthrough: Using a Configuration File to Define a Data Source

【讨论】:

【参考方案5】:

编辑 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 团队管理员 Visual Studio 团队(产品 Team, 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

【讨论】:

Windows Phone 现在也受支持,Visual Studio 2012 Update 2(当前为 CTP 4) 我有更新 1 但 DataTestMethod 和 DataRow 无法识别,这些属性在哪个库中? DataTestMethod有官方消息吗?它在哪个命名空间中,在哪个程序集中? 我发现 UnitTestFramework.dll 安装在我的计算机上,手动引用它后,我能够使用带有数据行的 [DataTestMethod] 属性编写方法,但我无法在 Visual 中获取测试资源管理器Studio 2012.3 找到方法。 我去了文件路径“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 应用商店项目。【参考方案6】:

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

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

    DemoTest_B10_A5.test

    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)  
    
    

【讨论】:

【参考方案7】:

实现起来非常简单——你应该使用TestContext属性和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);
        );

查看扩展methods 和samples 集以了解更多详情。

【讨论】:

这种方法有效,但不会为每组参数创建单独的测试用例。 您可以使用更复杂的值作为 TestProperty 值(例如“0-100”),在测试体中对其进行解析和处理。【参考方案8】:

此功能现在在 pre-release 中,可与 Visual Studio 2015 配合使用。

例如:

[TestClass]
public class UnitTest1

    [TestMethod]
    [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] (***.com/a/59162403/2540235) 这是正确的答案,应该被接受!真的对我有用!谢谢! [DataRow(1, 2, 3)] ?? @JohnB 大概是 abresult 的参数。 我是说第一组测试数据是错误的。我认为应该是:[DataRow(1, 2, 3)]【参考方案9】:

我无法让 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 中)。

【讨论】:

您应该将每个测试调用拆分为一个单独的测试,以便在其中一个中断时节省您的时间。 (我们都知道会发生) 是的,当然。在实践中,这就是它的做法。在这种情况下,我只是为了简单起见

以上是关于我们如何在 MSTest 中运行具有多个参数的测试方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何并行运行单元测试(MSTest)?

Jenkins Mstest 插件在尝试运行多个测试类别时去除命令行中的双引号

使用 mstest,我可以针对我支持的每种语言运行我的单元测试套件吗?

使用 MSTEST 和 Selenium 在并行 Web 测试中中止线程

在新的应用程序域中运行时,如何将标准输出转换为 mstest 输出?

VS2010 中的 MSTest - 如何一步启动所有负载测试