在 xUnit.net 中测试参数化,类似于 NUnit
Posted
技术标签:
【中文标题】在 xUnit.net 中测试参数化,类似于 NUnit【英文标题】:Test parameterization in xUnit.net similar to NUnit 【发布时间】:2012-02-24 23:52:25 【问题描述】:在xUnit.net框架中有没有类似NUnit以下特性的手段?
[Test, TestCaseSource("CurrencySamples")]
public void Format_Currency(decimal value, string expected)
static object[][] CurrencySamples = new object[][]
new object[] 0m, "0,00",
new object[] 0.0004m, "0,00",
new object[] 5m, "5,00",
new object[] 5.1m, "5,10",
new object[] 5.12m, "5,12",
new object[] 5.1234m, "5,12",
new object[] 5.1250m, "5,13", // round
new object[] 5.1299m, "5,13", // round
这将在 NUnit GUI 中生成 8 个单独的测试
[TestCase((string)null, Result = "1")]
[TestCase("", Result = "1")]
[TestCase(" ", Result = "1")]
[TestCase("1", Result = "2")]
[TestCase(" 1 ", Result = "2")]
public string IncrementDocNumber(string lastNum) return "some";
这将生成 5 个单独的测试并自动比较结果 (Assert.Equal()
)。
[Test]
public void StateTest(
[Values(1, 10)]
int input,
[Values(State.Initial, State.Rejected, State.Stopped)]
DocumentType docType
)
这将生成 6 个组合测试。无价之宝。
几年前我尝试过 xUnit 并喜欢它,但它缺少这些功能。没有他们就活不下去。有什么变化吗?
【问题讨论】:
将复杂对象作为参数发送到测试方法complex types in Unit test的完整指南 【参考方案1】:xUnit 提供了一种通过称为数据理论的东西来运行参数化测试的方法。这个概念等同于 NUnit 中的概念,但开箱即用的功能并不完整。
这是一个例子:
[Theory]
[InlineData("Foo")]
[InlineData(9)]
[InlineData(true)]
public void Should_be_assigned_different_values(object value)
Assert.NotNull(value);
在此示例中,xUnit 将为每个 InlineDataAttribute
运行一次 Should_format_the_currency_value_correctly
测试,每次将指定值作为参数传递。
数据理论是一个扩展点,您可以使用它来创建运行参数化测试的新方法。完成此操作的方法是创建新属性,这些属性检查并选择性地作用于测试方法的参数和返回值。
您可以在AutoFixture 的AutoData 和InlineAutoData 理论中找到如何扩展xUnit 的数据理论的一个很好的实际示例。
【讨论】:
显然是not allowed使用十进制字面量作为属性参数。 @RubenBartelink 您的链接未找到。请转至此处:blog.benhall.me.uk/2008/01/introduction-to-xunit-net-extensions 您需要 xUnit.net: Extensions(NuGet 包),否则[Theory]
属性不可用。
如果最推荐的 .NET 单元测试框架有一些文档就好了..
Google 说你的答案是 xUnit 文档。【参考方案2】:
让我在这里再举一个例子,以防它为某人节省一些时间。
[Theory]
[InlineData("goodnight moon", "moon", true)]
[InlineData("hello world", "hi", false)]
public void Contains(string input, string sub, bool expected)
var actual = input.Contains(sub);
Assert.Equal(expected, actual);
【讨论】:
【参考方案3】:在您的第一个请求中,您可以按照here 找到的示例进行操作。
您可以构造一个包含测试集合所需数据的静态类
using System.Collections.Generic;
namespace PropertyDataDrivenTests
public static class DemoPropertyDataSource
private static readonly List<object[]> _data = new List<object[]>
new object[] 1, true,
new object[] 2, false,
new object[] -1, false,
new object[] 0, false
;
public static IEnumerable<object[]> TestData
get return _data;
然后,使用 MemberData 属性,这样定义测试
public class TestFile1
[Theory]
[MemberData("TestData", MemberType = typeof(DemoPropertyDataSource))]
public void SampleTest1(int number, bool expectedResult)
var sut = new CheckThisNumber(1);
var result = sut.CheckIfEqual(number);
Assert.Equal(result, expectedResult);
或者如果您使用的是 C# 6.0,
[Theory]
[MemberData(nameof(PropertyDataDrivenTests.TestData), MemberType = typeof(DemoPropertyDataSource))]
MemberDataAttribute 的第一个参数允许您定义用作数据源的成员,因此您在重用方面具有相当大的灵活性。
【讨论】:
【参考方案4】:根据 xUnit 中的this article,您有三个“参数化”选项:
-
内联数据
类数据
会员资料
InlineData 示例
[Theory]
[InlineData(1, 2)]
[InlineData(-4, -6)]
[InlineData(2, 4)]
public void FooTest(int value1, int value2)
Assert.True(value1 + value2 < 7)
类数据示例
public class BarTestData : IEnumerable<object[]>
public IEnumerator<object[]> GetEnumerator()
yield return new object[] 1, 2 ;
yield return new object[] -4, -6 ;
yield return new object[] 2, 4 ;
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
[Theory]
[ClassData(typeof(BarTestData))]
public void BarTest(int value1, int value2)
Assert.True(value1 + value2 < 7)
会员数据示例
[Theory]
[MemberData(nameof(BazTestData))]
public void BazTest(int value1, int value2)
Assert.True(value1 + value2 < 7)
public static IEnumerable<object[]> BazTestData => new List<object[]>
new object[] 1, 2 ,
new object[] -4, -6 ,
new object[] 2, 4 ,
;
【讨论】:
【参考方案5】:我找到了一个库,它产生与 NUnit 的 [Values]
属性等效的功能,称为 Xunit.Combinatorial:
它允许您指定参数级值:
[Theory, CombinatorialData]
public void CheckValidAge([CombinatorialValues(5, 18, 21, 25)] int age,
bool friendlyOfficer)
// This will run with all combinations:
// 5 true
// 18 true
// 21 true
// 25 true
// 5 false
// 18 false
// 21 false
// 25 false
或者您可以隐含地让它计算出覆盖所有可能组合的最小调用次数:
[Theory, PairwiseData]
public void CheckValidAge(bool p1, bool p2, bool p3)
// Pairwise generates these 4 test cases:
// false false false
// false true true
// true false true
// true true false
【讨论】:
【参考方案6】:我在这里接受了所有答案,另外还使用了 XUnit 的 TheoryData<,>
泛型类型,为我的测试中的“MemberData”属性提供简单、易于阅读和键入安全的数据定义,如本例所示:
/// must be public & static for MemberDataAttr to use
public static TheoryData<int, bool, string> DataForTest1 = new TheoryData<int, bool, string>
1, true, "First" ,
2, false, "Second" ,
3, true, "Third"
;
[Theory(DisplayName = "My First Test"), MemberData(nameof(DataForTest1))]
public void Test1(int valA, bool valB, string valC)
Debug.WriteLine($"Running nameof(Test1) with values: valA, valB & valC ");
NB 为 .NET Core 使用 VS2017(15.3.3)、C#7 和 XUnit 2.2.0
【讨论】:
这很可爱。以上是关于在 xUnit.net 中测试参数化,类似于 NUnit的主要内容,如果未能解决你的问题,请参考以下文章