using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Xunit; using xUnitStudy.Model; namespace xUnitStudy.WebApi.Test { /// /// https://xunit.github.io/docs/comparisons /// [Trait("测试断言分组", "默认组")] public class UseAssertTest : IDisposable { #region 准备 public UseAssertTest() { } #endregion #region Equal [Fact] public void Equal_String_Test() { Assert.Equal("ping", "ping"); } /// /// 断言 string 相等 /// 设置大小写、行尾符、空白符号 比较选项 /// [Fact] public void Equal_String_Ignore_Test() { //ignoreCase:忽略字符大小写差异.如果为true,比较时忽略字符大小写 Assert.Equal("ABcdEF", "abcdef", ignoreCase: true); //ignoreLineEndingDifferences:忽略行尾结束符差异。设置为true,则将\rn、\r和\n视为等效。 Assert.Equal("One line\r\n", "one line\n", ignoreCase: true, ignoreLineEndingDifferences: true); //ignoreWhiteSpaceDifferences:忽略"空白"(空格、Tab)差异。设置为true,则将空格和制表符(以任何非零量)视为等效。 Assert.Equal("One line\r", "one line\n", ignoreCase: true, ignoreLineEndingDifferences: true, ignoreWhiteSpaceDifferences: true); } [Fact] public void Equal_Double_Test() { //注意:先舍入,然后再比较 //舍入规则:四舍五入 //精度范围[0,15]位小数 Assert.Equal(1.14d, 1.11d, precision: 1); Assert.Equal(1.15d, 1.19d, precision: 1); Assert //1.14d 约等于1.1 而1.15d 约等于1.2 所以不相等 .NotEqual(1.14d, 1.15d, precision: 1); //四舍五入到2位小数精度,相等 Assert.Equal(2.123d, 2.124d, 2); //四舍五入到3位小数精度,相等 Assert.Equal(3.1234d, 3.1231d, 3); //四舍五入到4位小数精度,不等 Assert.NotEqual(3.12345d, 3.12349d, 4); //四舍五入到整数,相等 Assert.Equal(15d, 15.111d, precision: 0); //没有小数位,四舍五入到整数 Assert.Equal(15d, 15d, precision: 0); } [Fact] public void Equal_Decimal_Test() { //注意:先舍入,然后再比较 //舍入规则:四舍五入 //精度范围[0,15]位小数 Assert.Equal(1.14M, 1.11M, precision: 1); Assert.Equal(1.15M, 1.19M, precision: 1); Assert //1.14M 约等于1.1 而1.15M 约等于1.2 所以不相等 .NotEqual(1.14M, 1.15M, precision: 1); //四舍五入到2位小数精度,相等 Assert.Equal(2.123M, 2.124M, 2); //四舍五入到3位小数精度,相等 Assert.Equal(3.1234M, 3.1231M, 3); //四舍五入到4位小数精度,不等 Assert.NotEqual(3.12345M, 3.12349M, 4); //四舍五入到整数,相等 Assert.Equal(15M, 15.111M, precision: 0); //没有小数位,四舍五入到整数 Assert.Equal(15M, 15M, precision: 0); } [Fact] public void Equal_Datetime_Test() { Assert.Equal(DateTime.Now, DateTime.Now.AddSeconds(1), TimeSpan.FromSeconds(2)); Assert.Equal(DateTime.Now, DateTime.Now.AddMinutes(1), TimeSpan.FromMinutes(2)); } /// /// Equal 泛型版本 /// 泛型版基本上都有简化写法 /// [Fact] public void Equal_Generic_T_Test() { //形如:Assert.Equal(Expected T, Actual T); //常见类型都可以简化,或是有更好的非泛型版,此时,一般用非泛型版 Assert.Equal("ping", "ping"); Assert //基本使用非泛型版本 .Equal("ping", "ping"); Assert.Equal(3, 3); Assert //简化为 .Equal(3, 3); Assert.Equal(3L, 3L); Assert //简化为 .Equal(3L, 3L); Assert.Equal(5.5d, 5.5d); Assert //简化为 .Equal(5.5d, 5.5d); Assert.Equal(5.5M, 5.5M); Assert //简化为 .Equal(5.5M, 5.5M); Assert.Equal(DateTime.Now.Date, DateTime.Now.Date); Assert //简化为 .Equal(DateTime.Now.Date, DateTime.Now.Date); //类或其它自定义结构比较,可以使用 var obj = new object(); Assert.Equal(obj, obj); Assert //简化为 .Equal(obj, obj); } /// /// Equal 实现了IEqualityComparer接口的泛型版本 /// [Fact] public void Equal_Generic_IEqualityComparer_Test() { //形如:Assert.Equal(Expected T, Actual T,IEqualityComparer comparer); //实现 IEqualityComparer 接口 var expected = new AssertEqualDemo() { Id = 1, Name = "zhansan" }; var actual = new AssertEqualDemo() { Id = 1, Name = "lisi" }; //实现 IEqualityComparer 接口的,可以是被比较对象自己实现接口,也可以是单独的类。 var comparer = new AssertEqualDemo(); Assert.Equal(expected, actual, comparer); Assert.//可以简写为 Equal(expected, actual, comparer); //id不一样,则不相等 expected.Id = 3; Assert.NotEqual(expected, actual, comparer); } /// /// 实现IEnumerable接口对象的 Equal比较 /// [Fact] public void Equal_Generic_IEnumerable_Test() { //对实现IEnumerable接口的对象进行 Equal比较 //形如:Equal(IEnumerable expected, IEnumerable actual); List expected = new List() { "first", "second" }; List actual = new List() { "first", "second" }; Assert.Equal>(expected, actual); Assert.//简写为 Equal(expected, actual); } /// /// 实现IEnumerable接口对象的 Equal 比较 /// 传入实现IEqualityComparer接口的比较器 /// [Fact] public void Equal_Generic_IEnumerable_IEqualityComparer_Test() { //对实现IEnumerable接口的对象进行 Equal比较 //形如:Equal(IEnumerable expected, IEnumerable actual,IEqualityComparer comparer) //传入实现了 IEqualityComparer 接口的比较参数 var expected = new List() { new AssertEqualDemo() { Id = 1, Name = "zhansan" }, new AssertEqualDemo() { Id = 2, Name = "lis" }, }; var actual = new List() { new AssertEqualDemo() { Id = 1, Name = "wangwu" }, new AssertEqualDemo() { Id = 2, Name = "zhaoliu" }, }; //实现 IEqualityComparer 接口的,可以是被比较对象自己实现接口,也可以是单独的类。 var comparer = new AssertEqualDemo(); Assert.Equal(expected, actual, comparer); Assert.//可以简写为 Equal(expected, actual, comparer); //id不一样,则不相等 expected[0].Id = 100; Assert.NotEqual(expected, actual, comparer); } #endregion #region NotEqual [Fact] public void NotEqual_String_Test() { Assert.NotEqual("ping", "ack"); } [Fact] public void NotEqual_Double_Test() { //注意:先舍入,然后再比较 //舍入规则:四舍五入 //精度范围[0,15]位小数 Assert //1.14d 约等于1.1 而1.15d 约等于1.2 所以不相等 .NotEqual(1.14d, 1.15d, precision: 1); //舍入到2位小数精度,相等 Assert.NotEqual(2.124d, 2.126d, 2); //舍入到3位小数精度,相等 Assert.NotEqual(3.1234d, 3.1239d, 3); //舍入到4位小数精度,不等 Assert.NotEqual(3.12346d, 3.12341d, 4); //舍入到整数,相等 Assert.NotEqual(16d, 15.111d, precision: 0); //没有小数位,舍入到整数 Assert.NotEqual(16d, 160d, precision: 0); } [Fact] public void NotEqual_Decimal_Test() { //注意:先舍入,然后再比较 //舍入规则:四舍五入 //精度范围[0,15]位小数 Assert //1.14M 约等于1.1 而1.15M 约等于1.2 所以不相等 .NotEqual(1.14M, 1.15M, precision: 1); //四舍五入到2位小数精度,不等 Assert.NotEqual(2.123M, 2.129M, 2); //四舍五入到3位小数精度,不等 Assert.NotEqual(3.1234M, 3.1236M, 3); //四舍五入到4位小数精度,不等 Assert.NotEqual(3.12345M, 3.12349M, 4); //四舍五入到整数,不等 Assert.NotEqual(15M, 15.501M, precision: 0); //没有小数位,四舍五入到整数 Assert.NotEqual(29M, 15M, precision: 0); } [Fact] public void NotEqual_Generic_T_Test() { //形如:Assert.NotEqual(Expected T, Actual T); Assert.NotEqual("ping", "ack"); Assert //基本使用非泛型版本 .NotEqual("ping", "ack"); Assert.NotEqual(3, 4); Assert //简化为 .NotEqual(3, 4); Assert.NotEqual(3L, 4L); Assert //简化为 .NotEqual(3L, 4L); Assert.NotEqual(5.5d, 6.5d); Assert //简化为 .NotEqual(5.5d, 6.5d); Assert.NotEqual(5.5M, 5.6M); Assert //简化为 .NotEqual(5.5M, 6.5M); Assert.NotEqual(DateTime.Now.Date, DateTime.Now.Date.AddDays(1)); Assert //简化为 .NotEqual(DateTime.Now.Date, DateTime.Now.Date.AddDays(1)); //类或其它自定义结构比较,可以使用 var obj = new object(); var obj2 = new object(); Assert.NotEqual(obj, obj2); Assert //简化为 .NotEqual(obj, obj2); } [Fact] public void NotEqual_Generic_IEqualityComparer_Test() { //形如:Assert.NotEqual(Expected T, Actual T,IEqualityComparer comparer); //实现 IEqualityComparer 接口 var expected = new AssertEqualDemo() { Id = 1, Name = "zhansan" }; var actual = new AssertEqualDemo() { Id = 1, Name = "lishi" }; //实现 IEqualityComparer 接口的,可以是被比较对象自己实现接口,也可以是单独的类。 var comparer = new AssertEqualDemo(); Assert.Equal(expected, actual, comparer); Assert.//可以简写为 Equal(expected, actual, comparer); //id不一样,则不相等 expected.Id = 3; Assert.NotEqual(expected, actual, comparer); } [Fact] public void NotEqual_Generic_IEnumerable_Test() { //对实现IEnumerable接口的对象进行 Equal比较 //形如:NotEqual(IEnumerable expected, IEnumerable actual) List expected = new List() { "first", "second", "third" }; List actual = new List() { "first", "second" }; Assert.NotEqual>(expected, actual); Assert.//简写为 NotEqual(expected, actual); } [Fact] public void NotEqual_Generic_IEnumerable_IEqualityComparer_Test() { //对实现IEnumerable接口的对象进行 Equal比较 //形如:NotEqual(IEnumerable expected, IEnumerable actual,IEqualityComparer comparer) //传入实现了 IEqualityComparer 接口的比较参数 var expected = new List() { new AssertEqualDemo() { Id = 1, Name = "zhansan" }, new AssertEqualDemo() { Id = 2, Name = "lis" }, }; var actual = new List() { new AssertEqualDemo() { Id = 1, Name = "wangwu" }, new AssertEqualDemo() { Id = 2, Name = "zhaoliu" }, }; //实现 IEqualityComparer 接口的,可以是被比较对象自己实现接口,也可以是单独的类。 var comparer = new AssertEqualDemo(); Assert.Equal(expected, actual, comparer); Assert.//可以简写为 Equal(expected, actual, comparer); //id不一样,则不相等 expected[0].Id = 100; Assert.NotEqual(expected, actual, comparer); } #endregion #region StrictEqual [Fact] public void StrictEqual_Test() { //使用类型的默认比较器验证两个对象是否严格相等,用法类似Equal //不支持自定义IEqualityComparer Assert.StrictEqual(1L, 1m); Person person1 = new Person() { Id = 2 }; Person person2 = new Person() { Id = 2 }; Person person3 = new Person() { Id = 1 }; IPerson person4 = person3; Assert.StrictEqual(person3, person4); } [Fact] public void NotStrictEqual_Test() { //使用类型的默认比较器验证两个对象是否严格相等,用法类似NotEqual //不支持自定义IEqualityComparer Assert.NotStrictEqual(2.55M, 3.55M); Person person1 = new Person() { Id = 2 }; Person person2 = new Person() { Id = 2 }; Person person3 = new Person() { Id = 1 }; IPerson person4 = person1; Assert.NotStrictEqual(person1, person2); } #endregion #region Same [Fact] public void Same_String_Test() { //验证两个引用类型的对象,是同一个实例 //注意:必须是引用类型,不能是值类型 //特别注明:sting类型,虽然是引用类型,但是比较特殊。采取复制策略,相同值可以(不严谨的说法)认为引用相同 string expected = "hell,world!"; string actual = "hell,world!"; Assert.Same(expected, actual); string expected2 = "hell,world!"; string actual2 = expected2; Assert.Same(expected2, actual2); } [Fact] public void Same_Object_Test() { object obj1 = new object(); object obj2 = new object(); object obj3 = obj1; object obj4 = obj2; Assert.Same(obj1, obj3); Assert.Same(obj2, obj4); } [Fact] public void Same_Class_Test() { object obj1 = new AssertEqualDemo() { Id = 1, Name = "zhangsan" }; object obj2 = new AssertEqualDemo() { Id = 1, Name = "zhangsan" }; object obj3 = obj1; object obj4 = obj2; Assert.Same(obj1, obj3); Assert.Same(obj2, obj4); } #endregion #region NotSame [Fact] public void NotSame_String_Test() { //验证两个引用类型的对象,是同一个实例 //注意:必须是引用类型,不能是值类型 //特别注明:sting类型,虽然是引用类型,但是比较特殊。采取复制策略,相同值可以(不严谨的说法)认为引用相同 string expected = "hell,world!"; string actual = "I am chinese!"; Assert.NotSame(expected, actual); Assert.NotSame("abc", "xyz"); } [Fact] public void NotSame_Object_Test() { object obj1 = new object(); object obj2 = new object(); Object obj3 = obj2; Assert.NotSame(obj1, obj2); Assert.NotSame(obj1, obj3); Assert.NotSame(new object(), new object()); } [Fact] public void NotSame_Class_Test() { object obj1 = new AssertEqualDemo() { Id = 1, Name = "zhangsan" }; object obj2 = new AssertEqualDemo() { Id = 1, Name = "zhangsan" }; object obj3 = obj1; object obj4 = obj2; Assert.NotSame(obj1, obj2); Assert.NotSame(obj3, obj4); Assert.NotSame(obj1, obj4); Assert.NotSame(obj2, obj3); } #endregion #region True [Fact] public void True_Condition_Test() { Assert.True(true); Assert.True("ping" == "ping"); Assert.True(2 == 1 + 1); Assert.True("ping" == "ping" && 2 == 1 + 1); } [Fact] public void True_Nullable_Test() { bool? expected = null; Assert.True(!expected.HasValue); int? expected2 = null; Assert.True(expected2 == null); expected2 = 2; Assert.True(2 == expected2.Value); } [Fact] public void True_Message_Test() { Assert.True(true, "userMessage"); Assert.True("ping" == "ping", "userMessage"); Assert.True(2 == 1 + 1, "userMessage"); int? nullableInt = null; Assert.True(null == nullableInt, "userMessage"); } #endregion #region False [Fact] public void False_Condition_Test() { Assert.False(false); Assert.False("ping" == "ack"); Assert.False(3 == 1 + 1); Assert.False("ping" == "ping" && 3 == 1 + 1); } [Fact] public void False_Nullable_Test() { bool? expected = null; Assert.False(expected.HasValue); int? expected2 = 3; Assert.False(expected2 == null); Assert.False(4 == expected2.Value); } [Fact] public void False_Message_Test() { Assert.False(false, "userMessage"); Assert.False("ping" == "ack", "userMessage"); Assert.False(2 == 1 + 3, "userMessage"); int? nullableInt = 3; Assert.False(null == nullableInt, "userMessage"); } #endregion #region True|False 可替代断言 /// /// 直接设置验证通过 /// [Fact] public void Pass_Test() { Assert.True(true, "用True断言替代"); } [Fact] public void Fail_Test() { //Assert.True(false, "用True断言替代"); } /// /// 大于 /// [Fact] public void GreaterThan_Test() { Assert //大于比较,用True(x > y) 替代 .True(2 > 1); int max = 5; int min = 2; Assert.True(max > min); } /// /// 小于 /// [Fact] public void LessThan_Test() { Assert //小于比较,用True(x < y) 替代 .True(2 < 3); int max = 5; int min = 2; Assert.True(min < max); } [Fact] public void NaN_Test() { //NaN=Not a Number,是否不为数字 //说明:在浮点数计算中,0除以0将得到NaN,正数除以0将得到PositiveInfinity,负数除以0将得到NegativeInfinity。 //浮点数运算从不引发异常 Assert.True(double.IsNaN(0 / 0d)); Assert.True(double.IsPositiveInfinity(1 / 0d)); Assert.True(double.IsNegativeInfinity(-1 / 0d)); } #endregion #region Null|Empty [Fact] public void Empty_Test() { List expected = new List(); Assert //针对于集合,为Empty,即是集合中元素的个数为0。但集合为空引用null值时将引发异常 .Empty(expected); } [Fact] public void NotEmpty_Test() { List expected = new List() { "first", "second" }; Assert //针对于集合,不为Empty,即是集合中元素的个数大于0。集合为空引用null值时将引发异常 .NotEmpty(expected); } [Fact] public void Null_Test() { Assert //null值,空引用 .Null(null); string exp = null; Assert.Null(exp); List list = null; Assert.Null(list); } [Fact] public void NotNull_Test() { Assert //null值,空引用 .NotNull(new object()); Assert.NotNull(""); Assert.NotNull(string.Empty); Assert.NotNull(new List()); Assert.NotNull(new List() { "first", "second" }); } #endregion #region Type|Assignable [Fact] public void IsType_Test() { //此形式,只在泛型不能使用时,才使用;应优先使用泛型版。 Assert.IsType(typeof(string), "aaaa"); //泛型版 Assert.IsType("hell,world!"); Assert.IsType(2); Assert.IsType(2L); Assert.IsType(2d); Assert.IsType(2M); Assert.IsType(DateTime.Now); Assert.IsType(new AssertEqualDemo()); } [Fact] public void IsNotType_Test() { //此形式,只在泛型不能使用时,才使用;应优先使用泛型版。 Assert.IsNotType(typeof(string), 22); //泛型版 Assert.IsNotType(2); Assert.IsNotType("hello"); Assert.IsNotType("521"); Assert.IsNotType(new object()); Assert.IsNotType("55555"); Assert.IsNotType("2018-08-03"); Assert.IsNotType(new object()); } [Fact] public void IsAssignableFrom_Test() { //可以从指定的类型派生 Assert.IsAssignableFrom(22); Person person = new Person() { Id = 1, FirstName = "first", LastName = "last" }; Assert. //接口派生 IsAssignableFrom(person); Teacher teacher = new Teacher() { Id = 1, FirstName = "first", LastName = "last", Grade = 2 }; Assert. //类继承 IsAssignableFrom(teacher); Assert //接口派生 .IsAssignableFrom(teacher); Assert //万源归宗 .IsAssignableFrom(teacher); } /// /// 断言非派生、继承关系 /// Assert.False(obj is Type)替代 /// [Fact] public void IsNotAssignableFrom_Test() { // Assert.False(obj is Type) 替代 //可以从指定的类型派生 Assert.False(88 is String); Assert.False(new object() is int); Person person = new Person() { Id = 1, FirstName = "first", LastName = "last" }; Teacher teacher = new Teacher() { Id = 2, FirstName = "first", LastName = "last", Grade = 2 }; IPerson person2 = new Person() { Id = 3, FirstName = "first", LastName = "last" }; Assert.False(person is Teacher); Assert.False(person2 is Teacher); } #endregion #region Contains For String [Fact] public void Contains_String_Test() { Assert.Contains("hello", "hello,world."); Assert.Contains("llo", "hello,world."); Assert.Contains("world", "hello,world."); } [Fact] public void Contains_String_Comparison_Ordinal_Test() { //StringComparison.Ordinal 二进制比较:最快,最严格 //进行非语言(non-linguistic)上的比较,对两个字符串进行byte级别的比较,比较结果严格而准确,性能非常好。 Assert.Contains("hello", "hello,world", StringComparison.Ordinal); Assert.Contains("llo", "hello,world", StringComparison.Ordinal); Assert.Contains("orld", "hello,world", StringComparison.Ordinal); } [Fact] public void Contains_String_Comparison_OrdinalIgnoreCase_Test() { //StringComparison.OrdinalIgnoreCase与StringComparison.Ordinal相同,只是不区分大小写 Assert.Contains("hello", "Hello,World", StringComparison.OrdinalIgnoreCase); Assert.Contains("llo", "Hello,World", StringComparison.OrdinalIgnoreCase); Assert.Contains("orld", "Hello,World", StringComparison.OrdinalIgnoreCase); } [Fact] public void Contains_String_Comparison_CurrentCulture_Test() { //StringComparison.CurrentCulture 默认的比较方式:使用区域敏感排序规则和当前区域比较字符串 //在当前的区域信息下进行比较,这是String.Compare在没有指定StringComparison的时候默认的比较方式 Assert.Contains("", "", StringComparison.CurrentCulture); Assert.Contains("orl", "hello,world", StringComparison.CurrentCulture); //设置特定区域 string s1 = "encyclopædia"; string s2 = "encyclopaedia"; //当前的区域信息是美国:s1与s2是相等的。 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); Assert.Contains(s1, s2, StringComparison.CurrentCulture); //当前的区域信息是se-SE,s1与s2是相等的 Thread.CurrentThread.CurrentCulture = new CultureInfo("se-SE"); Assert.DoesNotContain(s1, s2, StringComparison.CurrentCulture); } [Fact] public void Contains_String_Comparison_CurrentCultureIgnoreCase_Test() { //用法同:StringComparison.CurrentCulture,只是不区分大小写 Assert.Contains("A", "aBB", StringComparison.CurrentCultureIgnoreCase); Assert.Contains("worl", "Hello,World", StringComparison.CurrentCultureIgnoreCase); //设置特定区域 string s1 = "Encyclopædia"; string s2 = "encyclopaediA"; //当前的区域信息是美国:s1与s2是相等的。 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); Assert.Contains(s1, s2, StringComparison.CurrentCultureIgnoreCase); //当前的区域信息是se-SE,s1与s2是相等的 Thread.CurrentThread.CurrentCulture = new CultureInfo("se-SE"); Assert.DoesNotContain(s1, s2, StringComparison.CurrentCultureIgnoreCase); } [Fact] public void Contains_String_Comparison_InvariantCulture_Test() { //StringComparison.InvariantCulture:使用区域敏感排序规则和固定区域比较字符串 //在任何系统中(不同的culture)比较都将得到相同的结果,他是使用CultureInfo.InvariantCulture的静态成员CompareInfo来进行比较操作的. //StringComparison.InvariantCultureIgnoreCase与StringComparison.InvariantCulture,只是忽略大小写 Assert.Contains("ping", "ping", StringComparison.InvariantCulture); Assert.Contains("p", "ping", StringComparison.InvariantCulture); Assert.Contains("in", "ping", StringComparison.InvariantCulture); Assert.Contains("ing", "ping", StringComparison.InvariantCulture); //区域无关性 string s1 = "encyclopædia"; string s2 = "encyclopaedia"; Assert.Contains(s1, s2, StringComparison.InvariantCulture); //设置区为美国:无效 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); Assert.Contains(s1, s2, StringComparison.InvariantCulture); //设置区为se-SE:无效 Thread.CurrentThread.CurrentCulture = new CultureInfo("se-SE"); Assert.Contains(s1, s2, StringComparison.InvariantCulture); } [Fact] public void Contains_String_Comparison_InvariantCultureIgnoreCase_Test() { //StringComparison.InvariantCultureIgnoreCase与StringComparison.InvariantCulture,只是忽略大小写 Assert.Contains("ping", "PinG", StringComparison.InvariantCultureIgnoreCase); Assert.Contains("p", "PinG", StringComparison.InvariantCultureIgnoreCase); Assert.Contains("in", "PinG", StringComparison.InvariantCultureIgnoreCase); Assert.Contains("ing", "PinG", StringComparison.InvariantCultureIgnoreCase); //区域无关性 string s1 = "Encyclopædia"; string s2 = "encyclopaediA"; Assert.Contains(s1, s2, StringComparison.InvariantCultureIgnoreCase); //设置区为美国:无效 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); Assert.Contains(s1, s2, StringComparison.InvariantCultureIgnoreCase); //设置区为se-SE:无效 Thread.CurrentThread.CurrentCulture = new CultureInfo("se-SE"); Assert.Contains(s1, s2, StringComparison.InvariantCultureIgnoreCase); } #endregion #region Contains Collection [Fact] public void Contains_Generic_In_IEnumerable_Test() { //字符数组 var stringArray = new List() { "first", "second", "third", "four" }; Assert.Contains("first", stringArray); Assert //可以简化写法 .Contains("second", stringArray); //int 数组 var intArray = new List() { 1, 2, 3, 4, 5 }; Assert.Contains(2, intArray); Assert //可以简化写法 .Contains(3, intArray); //类组 //内部各项都相等,但实例(引用)不同,则不包含 var classArray = new List() { new Person(){ Id=1, FirstName="first1", LastName="last1"}, new Person(){ Id=2, FirstName="first2", LastName="last2"}, new Person(){ Id=3, FirstName="first3", LastName="last3"}, }; Person person1 = new Person() { Id = 1, FirstName = "first1", LastName = "last1" }; Person person2 = new Person() { Id = 2, FirstName = "first2", LastName = "last2" }; Person person3 = new Person() { Id = 3, FirstName = "first3", LastName = "last3" }; Assert.DoesNotContain(person1, classArray); Assert //简化写法 .DoesNotContain(person2, classArray); Assert //简化写法 .DoesNotContain(person3, classArray); //相同的引用才包含 classArray.Add(person1); classArray.Add(person2); classArray.Add(person3); Assert.Contains(person1, classArray); Assert.Contains(person2, classArray); Assert.Contains(person3, classArray); } [Fact] public void Contains_Generic_In_IEnumerable_IEqualityComparer_Test() { //以 IEqualityComparer 比较器为断言依据 Person person1 = new Person() { Id = 1, FirstName = "first1", LastName = "last1" }; Person person2 = new Person() { Id = 2, FirstName = "first2", LastName = "last2" }; Person person3 = new Person() { Id = 3, FirstName = "first3", LastName = "last3" }; var classArray = new List() { new Person() { Id = 1, FirstName = "ab", LastName = "cd" }, new Person() { Id = 2, FirstName = "ef", LastName = "g" }, new Person() { Id = 3, FirstName = "s", LastName = "b" }, }; //自定义比较器 IEqualityComparer equalityComparer = new Person(); Assert.Contains(person1, classArray, equalityComparer); Assert.Contains(person2, classArray, equalityComparer); Assert.Contains(person3, classArray, equalityComparer); } [Fact] public void Contains_Generic_IEnumerable_Filter_Test() { Person person1 = new Person() { Id = 1, FirstName = "first1", LastName = "last1" }; Person person2 = new Person() { Id = 2, FirstName = "first2", LastName = "last2" }; Person person3 = new Person() { Id = 3, FirstName = "first3", LastName = "last3" }; var classArray = new List() { person1, person2, person3, }; //Predicate 委托(入参T,返回 bool),作为筛选条件 Assert.Contains(classArray, person => person.Id == 1); Assert //简写为 .Contains(classArray, person => person.FirstName == "first1"); Assert //简写为 .Contains(classArray, person => person.Id == 3 && person.LastName == "last3"); } [Fact] public void Contains_Generic_In_IDictionary_Test() { //字符串 KeyValuePair sring_kv1 = new KeyValuePair("key1", "first"); KeyValuePair string_kv2 = new KeyValuePair("key2", "second"); KeyValuePair string_kv3 = new KeyValuePair("key3", "third"); IDictionary stringDic = new Dictionary(); stringDic.Add("key1", "first"); stringDic.Add("key2", "second"); stringDic.Add("key3", "third"); Assert.Contains("key1", stringDic); Assert.Contains>(sring_kv1, stringDic); //数字 KeyValuePair int_kv1 = new KeyValuePair("key1", 1); KeyValuePair int_kv2 = new KeyValuePair("key2", 2); KeyValuePair int_kv3 = new KeyValuePair("key3", 3); IDictionary intDic = new Dictionary(); intDic.Add("key1", 1); intDic.Add("key2", 2); intDic.Add("key3", 3); Assert.Contains("key1", intDic); Assert.Contains>(int_kv1, intDic); //类 Person person1 = new Person() { Id = 1, FirstName = "first1", LastName = "last1" }; Person person2 = new Person() { Id = 2, FirstName = "first2", LastName = "last2" }; Person person3 = new Person() { Id = 3, FirstName = "first3", LastName = "last3" }; KeyValuePair class_kv1 = new KeyValuePair("key1", person1); KeyValuePair class_kv2 = new KeyValuePair("key2", person2); KeyValuePair class_kv3 = new KeyValuePair("key3", person3); IDictionary classDic = new Dictionary(); classDic.Add("key1", person1); classDic.Add("key2", person2); classDic.Add("key3", person3); Assert.Contains("key1", classDic); Assert.Contains>(class_kv1, classDic); Assert.Contains(class_kv2, classDic); Assert.Contains(class_kv3, classDic); } [Fact] public void Contains_Generic_In_IReadOnlyDictionary_Test() { //类似 IDictionary //字符串 KeyValuePair sring_kv1 = new KeyValuePair("key1", "first"); KeyValuePair string_kv2 = new KeyValuePair("key2", "second"); KeyValuePair string_kv3 = new KeyValuePair("key3", "third"); IDictionary stringDic = new Dictionary(); stringDic.Add("key1", "first"); stringDic.Add("key2", "second"); stringDic.Add("key3", "third"); IReadOnlyDictionary stringReadOnlyDic = stringDic as IReadOnlyDictionary; Assert.Contains("key1", stringReadOnlyDic); Assert.Contains>(sring_kv1, stringReadOnlyDic); //类 Person person1 = new Person() { Id = 1, FirstName = "first1", LastName = "last1" }; Person person2 = new Person() { Id = 2, FirstName = "first2", LastName = "last2" }; Person person3 = new Person() { Id = 3, FirstName = "first3", LastName = "last3" }; KeyValuePair class_kv1 = new KeyValuePair("key1", person1); KeyValuePair class_kv2 = new KeyValuePair("key2", person2); KeyValuePair class_kv3 = new KeyValuePair("key3", person3); IDictionary classDic = new Dictionary(); classDic.Add("key1", person1); classDic.Add("key2", person2); classDic.Add("key3", person3); IReadOnlyDictionary classReadOnlyDic = classDic as IReadOnlyDictionary; Assert.Contains("key1", classReadOnlyDic); Assert.Contains>(class_kv1, classReadOnlyDic); Assert.Contains(class_kv2, classReadOnlyDic); Assert.Contains(class_kv3, classReadOnlyDic); } #endregion #region DoesNotContain 类似Contain 略过 #endregion #region InRange [Fact] public void InRange_Test() { Assert.InRange(5, 1, 10); Assert.InRange("b", "a", "d"); } [Fact] public void InRange_IComparable_Test() { IComparer comparer = new Person(); Person person1 = new Person() { Id = 1 }; Person person2 = new Person() { Id = 2 }; Person person3 = new Person() { Id = 3 }; Assert.InRange(person2, person1, person3, comparer); } #endregion #region NotInRange [Fact] public void NotInRange_Test() { Assert.NotInRange(5, 10, 100); Assert.NotInRange(20, 100, 2000); Assert.NotInRange("a", "b", "d"); Assert.NotInRange("z", "b", "d"); } [Fact] public void NotInRange_IComparable_Test() { IComparer comparer = new Person(); Person person1 = new Person() { Id = 1 }; Person person2 = new Person() { Id = 2 }; Person person3 = new Person() { Id = 3 }; Assert.NotInRange(person1, person2, person3, comparer); } #endregion #region Throws [Fact] public void Throws_Func_Test() { //方法不推荐使用:用泛型版本替代 var result = Assert.Throws(typeof(ArgumentNullException), () => { ArgumentNullException ex = new ArgumentNullException("userName"); throw ex; return ex; }); } [Fact] public void Throws_Action_Test() { //方法不推荐使用:用泛型版本替代 var result = Assert.Throws(typeof(FormatException), () => decimal.Parse("abc")); } [Fact] public async Task Throws_Async_Test() { //方法不推荐使用:用泛型版本替代 var result = await Assert.ThrowsAsync(typeof(FormatException), () => { return Task.Run(() => { int.Parse("abc"); }); }); } [Fact] public void Throws_Generic_Func_Test() { var result = Assert.Throws(() => ThrowAndReturnFormatException()); } [Fact] public void Throws_Generic_Action_Test() { var result = Assert.Throws(() => ThrowFormatException()); } [Fact] public void Throws_Generic_ParamName_Func_Test() { var paramName = "userName"; var result = Assert.Throws(paramName, () => ThrowAndReturnArgumentNullException(paramName)); } [Fact] public void Throws_Generic_ParamName_Action_Test() { var paramName = "userName"; var result = Assert.Throws(paramName, () => ThrowArgumentNullException(paramName)); } [Fact] public async Task Throws_Generic_Func_Async_Test() { var reslut = await Assert.ThrowsAsync(() => ThrowAndReturnFormatExceptionAsync()); } [Fact] public async Task Throws_Generic_ParamName_Async_Test() { var paramName = "userName"; var reslut = await Assert.ThrowsAsync(paramName, () => ThrowAndReturnArgumentNullExceptionAsync(paramName)); } [Fact] public void ThrowsAny_Func_Test() { var result = Assert.ThrowsAny(() => ThrowAndReturnFormatException()); } /// /// 断言异常或派生类异常 /// [Fact] public void ThrowsAny_Action_Test() { var result = Assert.ThrowsAny(() => ThrowFormatException()); } [Fact] public async Task ThrowsAny_Func_Async_Test() { var result = await Assert.ThrowsAnyAsync(() => ThrowAndReturnFormatExceptionAsync()); } [Fact] public void NotThrow_Exception_Test() { //2.0及更高版本,移除了 NotThrow断言 //使用TryCatch替代或自定断言扩展 Exception exception = null; try { //dosomething exception = null; } catch (Exception ex) { exception = ex; } Assert.Null(exception); } #endregion #region Matches [Fact] public void Matches_String_Test() { //用户名正则:大小写字线、数字、下划线组成,6-16位长度 var userNameReg = @"^[a-zA-Z]\w{5,15}$"; Assert.Matches(userNameReg, "bicijinlian"); Assert.Matches(userNameReg, "wangerxiao_1981"); //email正则 var emailReg = @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"; Assert.Matches(emailReg, "bicijinlian@163.com"); Assert.Matches(emailReg, "wangerxiao_1981@126.com"); Assert.Matches(emailReg, "15601716045@126.com"); } [Fact] public void DoesNotMatch_String_Test() { //用户名正则:大小写字线、数字、下划线组成,6-16位长度 var userNameReg = @"^[a-zA-Z]\w{5,15}$"; Assert.DoesNotMatch(userNameReg, "abcd0123456789abcdefg"); Assert.DoesNotMatch(userNameReg, "wang"); Assert.DoesNotMatch(userNameReg, "bicijinlian$"); Assert.DoesNotMatch(userNameReg, "wangerxiao_1981@163"); //email正则 var emailReg = @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"; Assert.DoesNotMatch(emailReg, "bicijinlian"); Assert.DoesNotMatch(emailReg, "wangerxiao_1981@126"); Assert.DoesNotMatch(emailReg, "15601716045126.com"); } [Fact] public void Matches_Regex_Test() { //用户名正则:大小写字线、数字、下划线组成,6-16位长度 var userNameReg = new System.Text.RegularExpressions.Regex(@"^[a-zA-Z]\w{5,15}$"); Assert.Matches(userNameReg, "bicijinlian"); Assert.Matches(userNameReg, "wangerxiao_1981"); //email正则 var emailReg = new System.Text.RegularExpressions.Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"); Assert.Matches(emailReg, "bicijinlian@163.com"); Assert.Matches(emailReg, "wangerxiao_1981@126.com"); Assert.Matches(emailReg, "15601716045@126.com"); } [Fact] public void DoesNotMatch_Regex_Test() { //用户名正则:大小写字线、数字、下划线组成,6-16位长度 var userNameReg = new System.Text.RegularExpressions.Regex(@"^[a-zA-Z]\w{5,15}$"); Assert.DoesNotMatch(userNameReg, "abcd0123456789abcdefg"); Assert.DoesNotMatch(userNameReg, "wang"); Assert.DoesNotMatch(userNameReg, "bicijinlian$"); Assert.DoesNotMatch(userNameReg, "wangerxiao_1981@163"); //email正则 var emailReg = new System.Text.RegularExpressions.Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"); Assert.DoesNotMatch(emailReg, "bicijinlian"); Assert.DoesNotMatch(emailReg, "wangerxiao_1981@126"); Assert.DoesNotMatch(emailReg, "15601716045126.com"); } #endregion #region StartWith | EndWith [Fact] public void StartsWith_Test() { Assert.StartsWith("Start", "StartAndEnd"); Assert.StartsWith("start", "StartAndEnd", StringComparison.CurrentCultureIgnoreCase); } [Fact] public void EndsWith_Test() { Assert.EndsWith("end", "startAndend"); Assert.EndsWith("end", "StartAndEnd", StringComparison.CurrentCultureIgnoreCase); } #endregion #region Single [Fact] public void Single_Collection_Test() { //只有一项的集合 List stringArray = new List() { "first" }; Assert.Single(stringArray); List decimalArray = new List() { 5.66M }; Assert.Single(decimalArray); List classArray = new List() { new Person() { Id = 2 } }; Assert.Single(classArray); } /// /// 集合中,指定项没有重复项 /// [Fact] public void Single_Collection_Expected_Test() { //集合中,指定的项只有一个,即是指定项在集合中没有重复项 //不被指定的项,可以有多个 List stringArray = new List() { "first", "second", "second" }; Assert //如果换成:List stringArray = new List() { "first","second","first" } //因为"first"有两项,则断言失败 .Single(stringArray, "first"); List decimalArray = new List() { 5.66M, 7.7M, 8.8M }; Assert.Single(decimalArray, 5.66M); Person person1 = new Person() { Id = 1 }; Person person2 = new Person() { Id = 2 }; Person person3 = new Person() { Id = 2 }; List classArray = new List() { person1, person2 }; Assert.Single(classArray, person1); List classArray2 = new List() { person1, person2, person3 }; Assert.True(true, "person2和person3是相同的项,所以 Assert.Single(classArray, person2) 会失败"); } [Fact] public void Single_Generic_Test() { //只有一项的集合(推荐简化写法) List stringArray = new List() { "first" }; Assert.Single(stringArray); List decimalArray = new List() { 5.66M }; Assert.Single(decimalArray); List classArray = new List() { new Person() { Id = 2 } }; Assert.Single(classArray); } [Fact] public void Single_Generic_Predicate_Test() { //集合中,指定表达式的项只有一个,即是Predicate<>筛选结果在集合中没有重复项 //不被指定的项,可以有多个 List stringArray = new List() { "first", "second", "second" }; Assert //如果换成:List stringArray = new List() { "first","second","first" } //因为"first"有两项,则断言失败 .Single(stringArray, s => s.StartsWith("f")); List decimalArray = new List() { 5.66M, 7.7M, 8.8M }; Assert.Single(decimalArray, d => d > 8); Person person1 = new Person() { Id = 1 }; Person person2 = new Person() { Id = 2 }; Person person3 = new Person() { Id = 2 }; List classArray = new List() { person1, person2, person3 }; Assert.Single(classArray, p => p.Id == 1); //Assert.Single(classArray, p => p.Id == 2),则失败 } #endregion [Fact] public void All_Test() { List items = new List() { "abc", "ac", "ad", "adddeddd" }; Assert.All(items, f => f.StartsWith("a")); } /// /// 相当于集合的自定义断言,实用意义不大 /// (Action参数中自定义代码) /// 看源代码,可能是集合类断言的基类 /// [Fact] public void Collection_Test() { //验证集合是否包含给定元素数量,满足元素检查器提供的条件。 List list = new List() { "first", "second" }; //参数Action[] elementInspectors,元素检查器,依次检查每个元素。 //元素检查器的总数必须与集合中元素的数量完全匹配 //看源代码:每个Action执行时,均不抛出异常,则断言通过 Action[] actions = new Action[2] { new Action (s=> {} ), new Action (s=>{}), }; Assert.Collection(list, actions); } #region ISet(集合) /// /// 子集断言 /// ISet是集合接口:包含不重复元素,实际集合的交、并、子集等运算 /// 实现了ISet接口的集合:HashSet和SortedSet /// [Fact] public void Subset_Test() { //"真实值"是"期望值"的子集 HashSet hset = new HashSet() { "first", "second", "third" }; HashSet sub1 = new HashSet() { "first", "second" }; HashSet sub2 = new HashSet() { "second", "third" }; //expectedSuperset 期望超集,真实值是子集 Assert.Subset(expectedSuperset: hset, actual: sub1); Assert.Subset(hset, sub2); //自己是自己子集 Assert.Subset(hset, hset); } /// /// 超集断言 /// [Fact] public void Superset_Test() { //"真实值"是"期望值"的超集 HashSet hset = new HashSet() { "first", "second", "third" }; HashSet sub1 = new HashSet() { "first", "second" }; HashSet sub2 = new HashSet() { "second", "third" }; //expectedSuperset 期望超集,真实值是子集 Assert.Superset(sub1, hset); Assert.Superset(sub2, hset); //自己是自己子的超集 Assert.Superset(hset, hset); } /// /// 真子集断言 /// [Fact] public void ProperSubset_Test() { //"真实值"是"期望值"的真子集 HashSet hset = new HashSet() { "first", "second", "third" }; HashSet sub1 = new HashSet() { "first", "second" }; HashSet sub2 = new HashSet() { "second", "third" }; //expectedSuperset 期望超集,真实值是子集 Assert.ProperSubset(expectedSuperset: hset, actual: sub1); Assert.ProperSubset(hset, sub2); //自己不是自己真子集 //Assert.ProperSubset(hset, hset); } /// /// 真超集断言 /// [Fact] public void ProperSuperset_Test() { //"真实值"是"期望值"的真超集 HashSet hset = new HashSet() { "first", "second", "third" }; HashSet sub1 = new HashSet() { "first", "second" }; HashSet sub2 = new HashSet() { "second", "third" }; //expectedSuperset 期望超集,真实值是子集 Assert.ProperSuperset(sub1, hset); Assert.ProperSuperset(sub2, hset); //自己不是自己子的真超集 //Assert.ProperSuperset(hset, hset); } #endregion #region 事件(暂未实现) /// /// 属性更改事件 /// [Fact] public void PropertyChanged_Test() { } /// /// 属性更改事件(异步) /// [Fact] public void PropertyChangedAsync_Test() { } /// /// 断言 特定事件被触发 /// [Fact] public void Raises_Test() { } /// /// 断言 事件或派生事件 被触发 /// [Fact] public void RaisesAny_Test() { } /// /// 断言 特定事件被触发(异步) /// [Fact] public void RaisesAsync_Test() { } /// /// 断言 事件或派生事件 被触发(异步) /// [Fact] public void RaisesAnyAsync_Test() { } #endregion #region 私有方法 private void ThrowArgumentNullException(string paramName) { ArgumentNullException ex = new ArgumentNullException(paramName, "message"); throw ex; } private ArgumentNullException ThrowAndReturnArgumentNullException(string paramName) { ArgumentNullException ex = new ArgumentNullException(paramName, "message"); throw ex; } private async Task ThrowAndReturnArgumentNullExceptionAsync(string paramName) { Func func = (para) => { ArgumentNullException ex = new ArgumentNullException(paramName, "message"); throw ex; }; var reslut = await Task.Run(() => func(paramName)); return reslut; } private void ThrowFormatException() { int.Parse("ping"); } private FormatException ThrowAndReturnFormatException() { FormatException exception = null; try { int.Parse("ping"); } catch (FormatException ex) { exception = ex; throw ex; } return exception; } private async Task ThrowFormatExceptionAsync() { await Task.Run(() => { int.Parse("ping"); }); } private async Task ThrowAndReturnFormatExceptionAsync() { Func func = () => { int.Parse("ping"); return new FormatException(); }; await Task.Run(() => func()); } #endregion #region 清理 public void Dispose() { } #endregion } }