.Net 5 XUnit 单元测试 电脑版发表于:2022/3/25 18:23 ![.netcore](https://img.tnblog.net/arcimg/hb/c857299a86d84ee7b26d181a31e58234.jpg ".netcore") >#.Net 5 XUnit 单元测试 [TOC] tn2>xUnit.net 是一个免费的、开源的、以社区为中心的 .NET Framework 单元测试工具。xUnit.net 由 NUnit v2 的原始发明者编写,是用于单元测试 C#、F#、VB.NET 和其他 .NET 语言的最新技术。xUnit.net 可与 ReSharper、CodeRush、TestDriven.NET 和 Xamarin 一起使用。它是.NET 基金会的一部分,按照他们的行为准则运作。它在Apache 2(OSI 批准的许可证)下获得许可。 ### Demo >#### 创建项目 ![](https://img.tnblog.net/arcimg/hb/6eca681761fc4c7887a4955258e42187.png) ![](https://img.tnblog.net/arcimg/hb/8d928d7a65964e6eae402ba9d4c6abc7.png) ![](https://img.tnblog.net/arcimg/hb/16d9c48010724b86aa829a6172185add.png) >#### 添加相关代码 ```csharp public class UnitTest1 { [Fact] public void PassingTest() { Assert.Equal(4, Add(2, 2)); } [Fact] public void FailingTest() { Assert.Equal(5, Add(2, 2)); } int Add(int x, int y) { return x + y; } } ``` >#### 测试代码 ![](https://img.tnblog.net/arcimg/hb/9c3f22324807464b9ea288cb6ea43f94.png) tn>`Assert`这个类是断言,它可以判断代码的结果是否是你想要的结果。(后续我们还会讲到) ### 属性 |NUnit 3.x | MSTest 15.x | xUnit.net 2.x | 注释 | | ------------ | ------------ | |[Test]|[TestMethod]|[Fact]|标记测试方法。| |[TestFixture]|[TestClass]|不适用|xUnit.net 不需要测试类的属性;它在程序集中的所有公共(导出)类中查找所有测试方法。 |Assert.That Record.Exception|[ExpectedException]|Assert.Throws Record.Exception xUnit.net 已经取消了 ExpectedException 属性以支持Assert.Throws.| |[SetUp]|[TestInitialize]|构造函数|我们认为使用[SetUp]通常是不好的。但是,您可以实现无参数构造函数作为直接替换。| |[TearDown]|[TestCleanup]|IDisposable.Dispose|我们认为使用`[TearDown]`通常是不好的。但是,您可以IDisposable.Dispose直接替换。| |[OneTimeSetUp]|[ClassInitialize]|IClassFixture<T>|要获得每个类的夹具设置,`IClassFixture<T>`请在您的测试类上实现。| |[OneTimeTearDown]|[ClassCleanup]|IClassFixture<T>|要获得每个类的夹具拆卸,`IClassFixture<T>`请在您的测试类上实现。| |不适用|不适用|ICollectionFixture<T>|要获得每个集合的夹具设置和拆卸,`ICollectionFixture<T>`请在您的测试集合上实施。| |[Ignore("reason")]|[Ignore]|[Fact(Skip="reason")]|在属性上设置 Skip 参数[Fact]以暂时跳过测试。| |[Property]|[TestProperty]|[Trait]|在测试中设置任意元数据| |[Theory]|[DataSource]|[Theory][XxxData]理论(数据驱动测试)。| ### 属性说明 >### Fact tn>表示测试结果永远成立的那些Unit Test,他们的输入条件不变。 tn2>`DisplayName`参数可以为每一个方法命名。 ![](https://img.tnblog.net/arcimg/hb/cb7683ac3525447a8889ec48bc03e478.png) tn2>`Skip`参数可以跳过当前方法,并说明原因。 ![](https://img.tnblog.net/arcimg/hb/64e955a3fa894deebac830134515e9ee.png) tn2>`Timeout`参数可以设置超时时间 ![](https://img.tnblog.net/arcimg/hb/007083a1dc1947b285dbff5eed5f44bb.png) >### Theory tn>Theory继承至Fact,它可以通过不同的传参来进行测试。 一般与InlineData配合使用 ```csharp public class TheoryTest { [Theory(DisplayName = "Theory Test")] [InlineData(1, 1, 2)] [InlineData(1, 2, 3)] [InlineData(2, 2, 4)] public void Demo03_Theory_Test(int num01, int num02, int result) { Assert.Equal<int>(result, num01 + num02); } } ``` ![](https://img.tnblog.net/arcimg/hb/ea9ec777266d426d86d4409cbd58ded1.png) >### MemberData tn2>`InlineData`方便了很多我们测试。 但是当不确定数据来源的时候,或者数据量很大的时候,总不可能一个一个加吧。 所以`MemberData`就出现了。 它可以提供不同的数据来源,比如:来源于数据库、xml、Excel、文本,我们也称之为**数据驱动**。 >######无参数数据源 tn2>MemberData特性第一个参数是成员名称(即方法,属性或字段的名称)。 第二个参数是指方法所需要的参数。 这里我们先演示属性传入的方式。 ```csharp public class MemberDataTest { public static IEnumerable<object[]> InputData_MemberData { get { var driverData = new List<object[]>(); //错的 driverData.Add(new object[] { 3, 1, 2 }); driverData.Add(new object[] { 8, 2, 3 }); driverData.Add(new object[] { 9, 3, 5 }); //对的 driverData.Add(new object[] { 3, 4, 7 }); driverData.Add(new object[] { 4, 5, 9 }); driverData.Add(new object[] { 5, 6, 11 }); return driverData; } } [Theory(DisplayName = "MemberData Theory Test")] [MemberData(nameof(InputData_MemberData))] public void MemberDataTest_Test(int num01, int num02, int result) { Assert.Equal<int>(result, num01 + num02); } } ``` ![](https://img.tnblog.net/arcimg/hb/c2ba87b21f824931a343a8050beedd29.png) >######带参数据源(方法) ```csharp public class MemberDataTest { public static IEnumerable<object[]> InputData_MemberData(string flag) { var driverData = new List<object[]>(); if (flag == "Default") { driverData.Add(new object[] { 1, 1, 2 }); driverData.Add(new object[] { 1, 2, 3 }); driverData.Add(new object[] { 2, 3, 5 }); } else { driverData.Add(new object[] { 3, 4, 7 }); driverData.Add(new object[] { 4, 5, 9 }); driverData.Add(new object[] { 5, 6, 11 }); } return driverData; } [Theory(DisplayName = "MemberData Theory Test")] [MemberData(nameof(InputData_MemberData), "Default")] public void MemberDataTest_Test(int num01, int num02, int result) { Assert.Equal<int>(result, num01 + num02); } } ``` ![](https://img.tnblog.net/arcimg/hb/e9a3e1711bab45c0b6766a9820057e79.png) >######定义类型 ```csharp public class MatrixTheoryData<T1, T2> : TheoryData<T1, T2> { public MatrixTheoryData(IEnumerable<T1> data1, IEnumerable<T2> data2) { Contract.Assert(data1 != null && data1.Any()); Contract.Assert(data2 != null && data2.Any()); foreach (T1 t1 in data1) { foreach (T2 t2 in data2) { Add(t1, t2); } } } } public static int[] Numbers = { 5, 6, 7 }; public static string[] Strings = { "Hello", "world!" }; public static MatrixTheoryData<string, int> MatrixData = new MatrixTheoryData<string, int>(Strings, Numbers); [Theory(DisplayName = "MemberData Theory Test")] [MemberData(nameof(MatrixData))] public void MemberDataTest_Test(string x,int y) { Assert.Equal(y, x.Length); } ``` ![](https://img.tnblog.net/arcimg/hb/c95c8b28a2f049c3928549002cc16ee2.png)