MSTest 是否与 NUnit 的 TestCase 等价?

我发现 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);
}
}
53275 次浏览

我知道这是一个迟到的回答,但希望它能帮助其他人。

我到处寻找一个优雅的解决方案,最后我自己写了一个。我们在超过20个项目中使用它,这些项目有成千上万的单元测试和成千上万的迭代。从来没有错过一个节拍。

Https://github.com/thwaitesy/mstesthacks

1) 安装 NuGet软件包。

2) 从 TestBase 继承您的测试类

public class UnitTest1 : TestBase
{ }

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

[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 属性添加到测试方法中,指向上面的 IEnumable 名称。这需要完全符合条件。

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


Assert.IsNotNull(number);
}

最终结果: 3个迭代,就像普通的 DataSource:)

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

我知道这是另一个迟到的答案,但是在我的团队中,我们使用 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);
}
}

您可以使用 Anonymous Type 和数组组合到 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上发布了更多的背景和细节。

微软最近发布了 “ MSTest V2”(参见 博客文章)。这允许您始终如一地(桌面,UWP,...)使用 DataRow属性!

 [TestClass]
public class StringFormatUtilsTest
{
[DataTestMethod]
[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);
}
}

同样,VisualStudioExpress 的测试资源管理器不能识别这些测试。但至少“完整的”VS 版本现在支持这一特性!

要使用它,只需安装 NuGet 软件包 测试框架测试适配器(从现在开始都是预发行版)。

老答案:

如果不必坚持使用 MSTest,而只是为了能够通过 Test Explorer 因为您只有 VisualStudioExpress 版本运行测试而使用它,那么这可能是您的一个解决方案:

有一个 VSIX 扩展可以通过 Test Explorer 运行 NUnit 测试。 但幸运的是 VsTestAdapter 附带了一个普通的 NuGet-Package也是!

因此,如果您是 VS Express 用户,只需安装 VsTestAdapter NuGet-Package 并通过 Test Explorer 运行您的 NUnit 测试/测试案例!


不幸的是,上述说法并不正确。虽然完全可以通过 Express 版本安装该软件包,但是它没有用处,因为它不能利用 Test Explorer。以前在 TestAdapter 的 旧版本上有一个附注,它已经从 2.0的描述页面中删除了:

请注意,它不适用于 VSExpress

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 文件输入的教程。

Khlr 给出了一个很好的详细解释,显然这种方法开始在 VS2015 Express 的桌面工作。 我试图留下评论,但我的名声不好,不允许我这样做。

让我在这里复制一下解决方案:

[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 软件包 测试框架测试适配器

问题是

错误 CS0433“ TestClassAttribute”类型同时存在于两者中 微软,VisualStudio,QualityTools,UnitTestFramework, Version = 10.0.0.0及 ‘ Microsoft. VisualStudio. TestPlatform. TestFramework,Version = 14.0.0.0

因此,请从项目的参考文献中删除 Microsoft.VisualStudio.QualityTools. UnitTestFramework

欢迎您编辑原始回复并删除这一条。

考虑使用 DynamicDataAttribute 动态数据属性:

NUnit 测试案例

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