MSTest有类似于NUnit的TestCase的等效功能吗?

152

我发现NUnit中的TestCase功能非常有用,因为它可以快速指定测试参数,而无需为每个测试编写单独的方法。MSTest中是否有类似的功能?

 [TestFixture]  
 public class StringFormatUtilsTest  
 {  
     [TestCase("tttt", "")]  
     [TestCase("", "")]  
     [TestCase("t3a4b5", "345")]  
     [TestCase("3&5*", "35")]  
     [TestCase("123", "123")]  
     public void StripNonNumeric(string before, string expected)  
     {  
         string actual = FormatUtils.StripNonNumeric(before);  
         Assert.AreEqual(expected, actual);  
     }  
 }  

类似的问题请参见https://dev59.com/5XRC5IYBdhLWcg3wSu97#12755816 - Michael Freidgeim
为什么不使用NUnit? - Mike de Klerk
1
@MikedeKlerk:如果你正在使用Entity Framework,Nunit非常慢...每次运行测试时,它显然会反射所有生成的类。 - Robert Harvey
一般来说,NUnit比MSTest具有更多的功能,如果您只是使用MSTest来能够在VS测试资源管理器中运行测试,则可以通过通过NuGet安装NUnit Test Adapter扩展来使用NUnit实现相同的功能。 - Stacked
1
尝试使用DataRow(),请参见:https://blogs.msdn.microsoft.com/devops/2016/06/17/taking-the-mstest-framework-forward-with-mstest-v2/ - Babak
NUnit和MSTest之间的属性比较https://www.lambdatest.com/blog/nunit-vs-xunit-vs-mstest/ - CharithJ
6个回答

114

微软最近宣布了“MSTest V2”(请参阅博客文章)。这允许您始终(桌面,UWP等)使用DataRow属性!

 [TestClass]  
 public class StringFormatUtilsTest  
 {  
     [DataTestMethod]  
     [DataRow("tttt", "")]  
     [DataRow("", "")]  
     [DataRow("t3a4b5", "345")]  
     [DataRow("3&5*", "35")]  
     [DataRow("123", "123")]  
     public void StripNonNumeric(string before, string expected)  
     {  
         string actual = FormatUtils.StripNonNumeric(before);  
         Assert.AreEqual(expected, actual);  
     }  
 } 

可惜,Visual Studio Express的Test Explorer无法识别这些测试。但至少“完整版”VS现在支持该功能!

要使用它,只需安装NuGet包MSTest.TestFrameworkMSTest.TestAdapter(目前都是预发布版本)。

旧回答:

如果不一定要坚持使用MSTest,而且仅仅是因为可以通过Test Explorer运行测试,因为你只有Visual Studio Express版本,那么这可能是一个解决方案:

VsTestAdapter VSIX扩展,可以通过Test Explorer运行NUnit测试。不幸的是,VS Express用户无法安装扩展......但幸运的是,VsTestAdapter还有一个纯NuGet-Package版本

所以,如果你是VS Express用户,只需安装VsTestAdapter NuGet-Package即可享受通过Test Explorer运行NUnit测试/测试用例!


不幸的是,前面提到的声明是不正确的。虽然可以在Express版本中安装该软件包,但它是无用的,因为它无法利用Test Explorer。以前旧版本的TestAdapter有一个附注,该附注已从2.0.0的说明页面中删除:

请注意,它不能与VS Express一起使用


4
在使用VS 2017时,MSTest“v2”现在是默认的测试框架。由于最新版本将支持OOTB,因此该信息可能应放置在答案的顶部。 - Marc L.
为了让这个与我的旧MS Unit测试项目一起工作,我不得不删除testsettings文件并降级到.NET Framework 4.5。 - Matthew Lock

37

我知道这是一个晚回答,但希望可以帮助其他人。

我到处寻找优雅的解决方案,最终自己编写了一个。我们在20多个项目中使用它,拥有数千个单元测试和数十万次迭代。从未出过任何差错。

https://github.com/Thwaitesy/MSTestHacks

1) 安装NuGet包。

2) 让你的测试类从TestBase继承。

public class UnitTest1 : TestBase
{ }

3) 创建一个返回IEnumerable的属性、字段或方法。

[TestClass]
public class UnitTest1 : TestBase
{
    private IEnumerable<int> Stuff
    {
        get
        {
            //This could do anything, get a dynamic list from anywhere....
            return new List<int> { 1, 2, 3 };
        }
    }
}

4) 将MSTest的DataSource属性添加到您的测试方法中,指向上面的IEnumerable名称。这需要是完全限定的。

[TestMethod]
[DataSource("Namespace.UnitTest1.Stuff")]
public void TestMethod1()
{
    var number = this.TestContext.GetRuntimeDataSourceObject<int>();

    Assert.IsNotNull(number);
}

最终结果:3次迭代就像正常的数据源一样 :)

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MSTestHacks;

namespace Namespace
{
    [TestClass]
    public class UnitTest1 : TestBase
    {
        private IEnumerable<int> Stuff
        {
            get
            {
                //This could do anything, get a dynamic list from anywhere....
                return new List<int> { 1, 2, 3 };
            }
        }

        [TestMethod]
        [DataSource("Namespace.UnitTest1.Stuff")]
        public void TestMethod1()
        {
            var number = this.TestContext.GetRuntimeDataSourceObject<int>();

            Assert.IsNotNull(number);
        }
    }
}

每个情况下是否也可以使用多个参数? - Lonefish
由于底层库发生了变化,这不适用于MsTest“v2”。这是VS15(VS 2017)的默认设置。 - Marc L.
4
如果您正在使用MSTest V2,那么现在有一个类似于NUnit的新测试用例提供程序。因此,不需要采用这种解决方法。 - Thwaitesy
这在VS 2015中似乎无法工作,应用程序配置文件没有动态填充,因此数据源找不到。 - Reed

15

我知道这是另一个晚回答,但在我的团队中,我们采用MS Test框架并开发了一种技术,它仅依赖于匿名类型来保存测试数据的数组,并使用LINQ循环遍历并测试每一行。它不需要额外的类或框架,并且往往比使用外部文件或连接数据库的数据驱动测试要更易于阅读和理解。实现起来也比数据驱动测试容易得多。

例如,假设你有一个像这样的扩展方法:

public static class Extensions
{
    /// <summary>
    /// Get the Qtr with optional offset to add or subtract quarters
    /// </summary>
    public static int GetQuarterNumber(this DateTime parmDate, int offset = 0)
    {
        return (int)Math.Ceiling(parmDate.AddMonths(offset * 3).Month / 3m);
    }
}
你可以使用匿名类型的数组和LINQ来编写类似这样的测试代码:
你可以使用匿名类型的数组和LINQ来编写这样的测试代码:
[TestMethod]
public void MonthReturnsProperQuarterWithOffset()
{
    // Arrange
    var values = new[] {
        new { inputDate = new DateTime(2013, 1, 1), offset = 1, expectedQuarter = 2},
        new { inputDate = new DateTime(2013, 1, 1), offset = -1, expectedQuarter = 4},
        new { inputDate = new DateTime(2013, 4, 1), offset = 1, expectedQuarter = 3},
        new { inputDate = new DateTime(2013, 4, 1), offset = -1, expectedQuarter = 1},
        new { inputDate = new DateTime(2013, 7, 1), offset = 1, expectedQuarter = 4},
        new { inputDate = new DateTime(2013, 7, 1), offset = -1, expectedQuarter = 2},
        new { inputDate = new DateTime(2013, 10, 1), offset = 1, expectedQuarter = 1},
        new { inputDate = new DateTime(2013, 10, 1), offset = -1, expectedQuarter = 3}
        // Could add as many rows as you want, or extract to a private method that
        // builds the array of data
    }; 
    values.ToList().ForEach(val => 
    { 
        // Act 
        int actualQuarter = val.inputDate.GetQuarterNumber(val.offset); 
        // Assert 
        Assert.AreEqual(val.expectedQuarter, actualQuarter, 
            "Failed for inputDate={0}, offset={1} and expectedQuarter={2}.", val.inputDate, val.offset, val.expectedQuarter); 
        }); 
    }
}

使用此技术时,建议使用格式化的消息,在Assert中包含输入数据,以帮助您确定哪一行导致测试失败。

我已经在AgileCoder.net上发布了更多背景和详细信息的博客文章。


7
最大的问题在于,如果数组中的任何一个测试用例失败,整个测试都会失败,而且不会再测试其他测试用例。 - ytoledano
这将创建可能相互影响的测试用例。 - BartoszKP
1
@BartoszKP 只有在被测试系统具有副作用的情况下,这可能不是最佳的技术。 - Gary.Ray
2
@Gary.Ray 当系统尚未产生副作用时,当测试未通过且另一位开发人员试图修复时,并浪费数小时来确定依赖关系是否重要。这是你永远不应该做的事情,无论何时。 - BartoszKP

8
Khlr提供了详细的解释,并且显然这种方法在VS2015 Express for Desktop 中开始起作用。我试图留下评论,但是由于声望不够,我无法这样做。
让我在这里复制解决方案:
[TestClass]  
 public class StringFormatUtilsTest  
 {  
     [TestMethod]  
     [DataRow("tttt", "")]  
     [DataRow("", "")]  
     [DataRow("t3a4b5", "345")]  
     [DataRow("3&amp;amp;5*", "35")]  
     [DataRow("123", "123")]  
     public void StripNonNumeric(string before, string expected)  
     {  
         string actual = FormatUtils.StripNonNumeric(before);  
         Assert.AreEqual(expected, actual);  
     }  
 } 

要使用它,只需安装NuGet包MSTest.TestFrameworkMSTest.TestAdapter
一个问题是

错误 CS0433:“TestClassAttribute”类型在“Microsoft.VisualStudio.QualityTools.UnitTestFramework,版本=10.0.0.0”和“Microsoft.VisualStudio.TestPlatform.TestFramework,版本=14.0.0.0”中都存在。

因此,请从项目的引用中删除Microsoft.VisualStudio.QualityTools.UnitTestFramework
欢迎您编辑原始回复并删除此回复。

3
请考虑使用DynamicDataAttributeNUnit测试用例
private static readonly IEnumerable<TestCaseData> _testCases = new[]
{
    new TestCaseData("input value 1").Returns(new NameValueCollection { { "a", "b" } }),
    new TestCaseData("input value 2").Returns(new NameValueCollection { { "a", "b" } }),
    /* .. */
};

[TestCaseSource(nameof(_testCases))]
public NameValueCollection test_test(string str)
{
    var collection = new NameValueCollection();
    collection.TestedMethod(str);
    return collection;
}

MSTest测试用例

private static IEnumerable<object[]> _testCases
{
    get
    {
        return new[]
        {
            new object[] { "input value 1", new NameValueCollection { { "a", "b" } } },
            new object[] { "input value 2", new NameValueCollection { { "a", "b" } } },
            /* .. */
        };
    }
}

[TestMethod]
[DynamicData(nameof(_testCases))]
public void test_test(string str, NameValueCollection expectedResult)
{
    var collection = new NameValueCollection();
    collection.TestedMethod(str);

    CollectionAssert.AreEqual(expectedResult, collection);
}

0

MSTest有DataSource属性,可以让您提供数据库表、csv、xml等数据。 我使用过它,而且效果很好。 我不知道是否有一种方法可以将数据放在上面作为属性,就像您的问题中那样,但是设置外部数据源非常容易,并且文件可以包含在项目中。 从我开始到一个小时后,测试就已经运行了,而我并不是自动化测试专家。

https://msdn.microsoft.com/en-us/library/ms182527.aspx?f=255&MSPPError=-2147217396基于数据库输入提供了完整的教程。

http://www.rhyous.com/2015/05/11/row-tests-or-paramerterized-tests-mstest-xml/ 基于XML文件输入提供了教程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接