走进 .Net 单元测试
走进 .Net 单元测试
Intro
“不会写单元测试的程序员不是合格的程序员,不写单元测试的程序员不是优秀程序员。”
—— 一只想要成为一个优秀程序员的渣逼程序猿。
那么问题来了,什么是单元测试,如何做单元测试。
单元测试定义
按照维基百科上的说法,单元测试(Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。 程序单元是应用的最小可测试部件。在面向对象编程中,最小单元就是方法,包括基类、抽象类、或者派生类(子类)中的方法。 按照通俗的理解,一个单元测试判断某个特定场条件下某个特定方法的行为,如斐波那契数列算法,冒泡排序算法。
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。 对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义, 如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。 总的来说,单元就是人为规定的最小的被测功能模块。 单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。
进行单元测试的好处
它是一种验证行为
程序中的每一项功能都是测试来验证它的正确性。
它是一种设计行为
编写单元测试将使我们从调用者观察、思考。 特别是先写测试(test-first),迫使我们把程序设计成易于调用和可测试的,有利于程序的解耦和模块化。
它是一种编写文档的行为
单元测试是一种无价的文档,它是展示函数或类如何使用的最佳文档。这份文档是可编译、可运行的,并且它保持最新,永远与代码同步。
它具有回归性
自动化的单元测试避免了代码出现回归,编写完成之后,可以随时随地的快速运行测试。
高效
自动化的单元测试节省了开发上调试BUG的时间,绝大多数BUG可以通过单元测试测试出来,并且可以减少测试人员的测试时间。有时候通过写单元测试能够更好的完善自己程序的逻辑,让程序变得更加美好。
—— 单元测试的优点 http://jingyan.baidu.com/article/d713063522ab4e13fdf47533.html
单元测试的原则:
- 可重复运行的
- 持续长期有效,并且返回一致的结果
- 在内存中运行,没有外部依赖组件(比如说真实的数据库,真实的文件存储等)
- 快速返回结果
- 一个测试方法只测试一个问题
VS单元测试 【MsTest】使用
VS单元测试的主要类:Assert、StringAssert、CollectionAssert,具体可参照 MSDN介绍
有些时候我们需要对测试的方法用到的数据或配置进行初始化,有几个特殊的测试方法。
如果需要针对测试中的所有虚拟用户迭代仅执行一次初始化操作,请使用 TestInitializeAttribute。
初始化方法的运行顺序如下:
- 用 AssemblyInitializeAttribute 标记的方法。
- 用 ClassInitializeAttribute 特性标记的方法。
- 用 TestInitializeAttribute 特性标记的方法。
- 用 TestMethodAttribute 特性标记的方法。
单元测试 使用示例
1 using Microsoft.VisualStudio.TestTools.UnitTesting; 2 3 namespace ConsoleApplication1Test 4 { 5 [TestClass] 6 public class MainTest 7 { 8 #region TestFail 9 10 [TestMethod] 11 public void TestFail0() 12 { 13 Assert.Fail(); 14 } 15 16 [TestMethod] 17 public void TestFail1() 18 { 19 Assert.Fail("Test is fail"); 20 } 21 22 [TestMethod] 23 public void TestFail2() 24 { 25 Assert.Fail("Test3 is fail,{0}", "hahaha"); 26 } 27 #endregion 28 29 #region TestInconclusive 忽略 30 [TestMethod] 31 public void TestInconclusive0() 32 { 33 Assert.Inconclusive(); 34 } 35 36 [TestMethod] 37 public void TestInconclusive1() 38 { 39 Assert.Inconclusive("Inconclusive"); 40 } 41 42 [TestMethod] 43 public void TestInconclusive2() 44 { 45 Assert.Inconclusive("Inconclusive,{0}", "hehehe"); 46 } 47 #endregion 48 49 #region LogicTest 50 51 #region Null 52 [TestMethod] 53 public void IsNullTest() 54 { 55 Assert.IsNull(null); 56 } 57 58 [TestMethod] 59 public void IsNotNullTest() 60 { 61 Assert.IsNotNull(1); 62 } 63 #endregion 64 65 #region True || False 66 [TestMethod] 67 public void IsTrueTest() 68 { 69 Assert.IsTrue(1 == 1); 70 } 71 72 [TestMethod] 73 public void IsFalseTest() 74 { 75 Assert.IsFalse(1 > 2); 76 } 77 #endregion 78 79 #region AreSame 80 [TestMethod] 81 public void AreSameTest() 82 { 83 //不要向 AreSame() 传递值类型的值,因为他们转换为 Object 后永久不会相等,值类型的值比较请使用 AreEqual() 84 Assert.AreSame(1, 1); 85 } 86 87 [TestMethod] 88 public void AreSameTest1() 89 { 90 object obj = new object(), obj1 = obj; 91 Assert.AreSame(obj, obj1, "same"); 92 } 93 94 [TestMethod] 95 public void StringAreSameTest0() 96 { 97 string str1 = "hello", str2 = "hello"; 98 Assert.AreSame(str1, str2); 99 } 100 101 [TestMethod] 102 public void StringAreSameTest1() 103 { 104 string str1 = "hello", str2 = "Hello"; 105 Assert.AreSame(str1, str2); 106 } 107 108 [TestMethod] 109 public void AreNotSameTest() 110 { 111 object obj = new object(), obj1 = new object(); 112 Assert.AreNotSame(obj, obj1); 113 } 114 #endregion 115 116 #region AreEqual 117 [TestMethod] 118 public void AreEqualTest() 119 { 120 Assert.AreEqual(1, 1); 121 } 122 123 [TestMethod] 124 public void AreNotEqualTest() 125 { 126 Assert.AreNotEqual(1, 2); 127 } 128 129 [TestMethod] 130 public void AreEqualTest1() 131 { 132 object obj = new object(), obj1 = obj; 133 Assert.AreEqual(obj, obj1); 134 } 135 136 [TestMethod] 137 public void AreNotEqualTest1() 138 { 139 object obj = new object(), obj1 = new object(); 140 Assert.AreNotEqual(obj, obj1); 141 } 142 143 [TestMethod] 144 public void AreEqualTest2() 145 { 146 object obj = new object(), obj1 = new object(); 147 Assert.AreEqual(obj, obj1); 148 // Assert.Equals()不用于断言,请使用 Assert.AreEquals() 或 Assert.AreNotEquals() 149 //Assert.Equals(obj, obj1); 150 } 151 152 [TestMethod] 153 public void StringAreEqualTest0() 154 { 155 string str = "hello", str1 = "hello"; 156 Assert.AreEqual(str, str1); 157 } 158 159 [TestMethod] 160 public void StringAreEqualTest1() 161 { 162 string str = "hello", str1 = "Hello"; 163 Assert.AreEqual(str, str1, true); 164 } 165 #endregion 166 167 #region IsInstanceOfType 168 169 [TestMethod] 170 public void IsInstanceOfTypeTest() 171 { 172 B b = new B(); 173 Assert.IsInstanceOfType(b, typeof(A)); 174 } 175 176 [TestMethod] 177 public void IsNotInstanceOfTypeTest() 178 { 179 A a = new A(); 180 Assert.IsNotInstanceOfType(a, typeof(B)); 181 } 182 #endregion 183 184 #endregion 185 186 #region 测试初始化和清理 187 [AssemblyInitialize()] 188 public static void AssemblyInit(TestContext context) 189 { 190 System.Console.WriteLine("AssemblyInit " + context.TestName); 191 } 192 193 [ClassInitialize()] 194 public static void ClassInit(TestContext context) 195 { 196 System.Console.WriteLine("ClassInit " + context.TestName); 197 } 198 199 [TestInitialize] 200 public void Initialize() 201 { 202 System.Console.WriteLine("TestMethodInit"); 203 } 204 205 [TestCleanup] 206 public void Cleanup() 207 { 208 System.Console.WriteLine("TestMethodCleanup"); 209 } 210 211 [ClassCleanup] 212 public static void ClassCleanup() 213 { 214 System.Console.WriteLine("ClassCleanup"); 215 } 216 217 [AssemblyCleanup] 218 public static void AssemblyCleanup() 219 { 220 System.Console.WriteLine("AssemblyCleanup"); 221 } 222 #endregion 223 } 224 225 public class A { } 226 227 public class B : A { } 228 229 }
MsTest 和 Nunit区别
MS Test框架是Visual Studio自带的测试框架,可以通过新建一个Unit Test Project工程, 也可以建一个Class Libary,然后添加对Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll的引用。 然后就是创建测试用例,进行测试即可。
NUnit Test框架是一个xUnit家族种的第4个主打产品,完全由C#语言来编写,支持所有的.Net语言。 使用NUnit框架,我们需要下载安装包,安装后使用独立客户端进行使用。使用方法与MS Test类似
有一些是NUnit中的,但是MS Test框架中是没有的: - Assert.IsNaN - Assert.IsEmpty - Assert.IsNotEmpty - Assert.Greater - Assert.GreaterOrEqual - Assert.Less - Assert.LessOrEqual - Assert.IsAssignableFrom - Assert.IsNotAssignableFrom - Assert.Igore - CollectionAssert.IsEmpty - CollectionAssert.IsNotEmpty - StringAssert.AreEqualIgnoringCase - StringAssert.IsMatch - FileAssert.AreEqual - FileAssert.AreNotEqual
同时支持两种测试框架
可以通过宏判断来同时支持这两个框架,在测试前添加以下代码:
1 #if !NUNIT 2 using Microsoft.VisualStudio.TestTools.UnitTesting; 3 using Category = Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute; 4 #else 5 using NUnit.Framework; 6 using TestClass = NUnit.Framework.TestFixtureAttribute; 7 using TestMethod = NUnit.Framework.TestAttribute; 8 using TestInitialize = NUnit.Framework.SetUpAttribute; 9 using TestCleanup = NUnit.Framework.TearDownAttribute; 10 using TestContext = System.Object; 11 using ClassCleanup = NUnit.Framework.TestFixtureTearDownAttribute; 12 using ClassInitialize = NUnit.Framework.TestFixtureSetUpAttribute; 13 #endif
Nunit测试使用示例
1 #region NUNIT 2 3 /// <summary> 4 /// This test fixture attempts to exercise all the syntactic 5 /// variations of Assert without getting into failures, errors 6 /// or corner cases.Thus, some of the tests may be duplicated 7 /// in other fixtures. 8 /// 9 /// Each test performs the same operations using the classic 10 /// syntax(if available) and the new syntax in both the 11 /// helper-based and inherited forms. 12 /// 13 /// This Fixture will eventually be duplicated in other 14 /// supported languages. 15 /// </summary> 16 [TestFixture] 17 public class AssertSyntaxTests : AssertionHelper 18 { 19 #region Simple Constraint Tests 20 [Test] 21 public void IsNull() 22 { 23 object nada = null; 24 25 // Classic syntax 26 Assert.IsNull(nada); 27 28 // Constraint Syntax 29 Assert.That(nada, Is.Null); 30 31 // Inherited syntax 32 Expect(nada, Null); 33 } 34 35 [Test] 36 public void IsNotNull() 37 { 38 // Classic syntax 39 Assert.IsNotNull(42); 40 41 // Constraint Syntax 42 Assert.That(42, Is.Not.Null); 43 44 // Inherited syntax 45 Expect(42, Not.Null); 46 } 47 48 [Test] 49 public void IsTrue() 50 { 51 // Classic syntax 52 Assert.IsTrue(2 + 2 == 4); 53 54 // Constraint Syntax 55 Assert.That(2 + 2 == 4, Is.True); 56 Assert.That(2 + 2 == 4); 57 58 // Inherited syntax 59 Expect(2 + 2 == 4, True); 60 Expect(2 + 2 == 4); 61 } 62 63 [Test] 64 public void IsFalse() 65 { 66 // Classic syntax 67 Assert.IsFalse(2 + 2 == 5); 68 69 // Constraint Syntax 70 Assert.That(2 + 2 == 5, Is.False); 71 72 // Inherited syntax 73 Expect(2 + 2 == 5, False); 74 } 75 76 [Test] 77 public void IsNaN() 78 { 79 double d = double.NaN; 80 float f = float.NaN; 81 82 // Classic syntax 83 Assert.IsNaN(d); 84 Assert.IsNaN(f); 85 86 // Constraint Syntax 87 Assert.That(d, Is.NaN); 88 Assert.That(f, Is.NaN); 89 90 // Inherited syntax 91 Expect(d, NaN); 92 Expect(f, NaN); 93 } 94 95 [Test] 96 public void EmptyStringTests() 97 { 98 // Classic syntax 99 Assert.IsEmpty(""); 100 Assert.IsNotEmpty("Hello!"); 101 102 // Constraint Syntax 103 Assert.That("", Is.Empty); 104 Assert.That("Hello!", Is.Not.Empty); 105 106 // Inherited syntax 107 Expect("", Empty); 108 Expect("Hello!", Not.Empty); 109 } 110 111 [Test] 112 public void EmptyCollectionTests() 113 { 114 // Classic syntax 115 Assert.IsEmpty(new bool[0]); 116 Assert.IsNotEmpty(new int[] { 1, 2, 3 }); 117 118 // Constraint Syntax 119 Assert.That(new bool[0], Is.Empty); 120 Assert.That(new int[] { 1, 2, 3 }, Is.Not.Empty); 121 122 // Inherited syntax 123 Expect(new bool[0], Empty); 124 Expect(new int[] { 1, 2, 3 }, Not.Empty); 125 } 126 #endregion 127 128 #region TypeConstraint Tests 129 [Test] 130 public void ExactTypeTests() 131 { 132 // Classic syntax workarounds 133 Assert.AreEqual(typeof(string), "Hello".GetType()); 134 Assert.AreEqual("System.String", "Hello".GetType().FullName); 135 Assert.AreNotEqual(typeof(int), "Hello".GetType()); 136 Assert.AreNotEqual("System.Int32", "Hello".GetType().FullName); 137 138 // Constraint Syntax 139 Assert.That("Hello", Is.TypeOf(typeof(string))); 140 Assert.That("Hello", Is.Not.TypeOf(typeof(int))); 141 142 // Inherited syntax 143 Expect("Hello", TypeOf(typeof(string))); 144 Expect("Hello", Not.TypeOf(typeof(int))); 145 } 146 147 [Test] 148 public void InstanceOfTests() 149 { 150 // Classic syntax 151 Assert.IsInstanceOf(typeof(string), "Hello"); 152 Assert.IsNotInstanceOf(typeof(string), 5); 153 154 // Constraint Syntax 155 Assert.That("Hello", Is.InstanceOf(typeof(string))); 156 Assert.That(5, Is.Not.InstanceOf(typeof(string))); 157 158 // Inherited syntax 159 Expect("Hello", InstanceOf(typeof(string))); 160 Expect(5, Not.InstanceOf(typeof(string))); 161 } 162 163 [Test] 164 public void AssignableFromTypeTests() 165 { 166 // Classic syntax 167 Assert.IsAssignableFrom(typeof(string), "Hello"); 168 Assert.IsNotAssignableFrom(typeof(string), 5); 169 170 // Constraint Syntax 171 Assert.That("Hello", Is.AssignableFrom(typeof(string))); 172 Assert.That(5, Is.Not.AssignableFrom(typeof(string))); 173 174 // Inherited syntax 175 Expect("Hello", AssignableFrom(typeof(string))); 176 Expect(5, Not.AssignableFrom(typeof(string))); 177 } 178 #endregion 179 180 #region StringConstraint Tests 181 [Test] 182 public void SubstringTests() 183 { 184 string phrase = "Hello World!"; 185 string[] array = new string[] { "abc", "bad", "dba" }; 186 187 // Classic Syntax 188 StringAssert.Contains("World", phrase); 189 190 // Constraint Syntax 191 Assert.That(phrase, Does.Contain("World")); 192 // Only available using new syntax 193 Assert.That(phrase, Does.Not.Contain("goodbye")); 194 Assert.That(phrase, Does.Contain("WORLD").IgnoreCase); 195 Assert.That(phrase, Does.Not.Contain("BYE").IgnoreCase); 196 Assert.That(array, Is.All.Contains("b")); 197 198 // Inherited syntax 199 Expect(phrase, Contains("World")); 200 // Only available using new syntax 201 Expect(phrase, Not.Contains("goodbye")); 202 Expect(phrase, Contains("WORLD").IgnoreCase); 203 Expect(phrase, Not.Contains("BYE").IgnoreCase); 204 Expect(array, All.Contains("b")); 205 } 206 207 [Test] 208 public void StartsWithTests() 209 { 210 string phrase = "Hello World!"; 211 string[] greetings = new string[] { "Hello!", "Hi!", "Hola!" }; 212 213 // Classic syntax 214 StringAssert.StartsWith("Hello", phrase); 215 216 // Constraint Syntax 217 Assert.That(phrase, Does.StartWith("Hello")); 218 // Only available using new syntax 219 Assert.That(phrase, Does.Not.StartWith("Hi!")); 220 Assert.That(phrase, Does.StartWith("HeLLo").IgnoreCase); 221 Assert.That(phrase, Does.Not.StartWith("HI").IgnoreCase); 222 Assert.That(greetings, Is.All.StartsWith("h").IgnoreCase); 223 224 // Inherited syntax 225 Expect(phrase, StartsWith("Hello")); 226 // Only available using new syntax 227 Expect(phrase, Not.StartsWith("Hi!")); 228 Expect(phrase, StartsWith("HeLLo").IgnoreCase); 229 Expect(phrase, Not.StartsWith("HI").IgnoreCase); 230 Expect(greetings, All.StartsWith("h").IgnoreCase); 231 } 232 233 [Test] 234 public void EndsWithTests() 235 { 236 string phrase = "Hello World!"; 237 string[] greetings = new string[] { "Hello!", "Hi!", "Hola!" }; 238 239 // Classic Syntax 240 StringAssert.EndsWith("!", phrase); 241 242 // Constraint Syntax 243 Assert.That(phrase, Does.EndWith("!")); 244 // Only available using new syntax 245 Assert.That(phrase, Does.Not.EndWith("?")); 246 Assert.That(phrase, Does.EndWith("WORLD!").IgnoreCase); 247 Assert.That(greetings, Is.All.EndsWith("!")); 248 249 // Inherited syntax 250 Expect(phrase, EndsWith("!")); 251 // Only available using new syntax 252 Expect(phrase, Not.EndsWith("?")); 253 Expect(phrase, EndsWith("WORLD!").IgnoreCase); 254 Expect(greetings, All.EndsWith("!")); 255 } 256 257 [Test] 258 public void EqualIgnoringCaseTests() 259 { 260 string phrase = "Hello World!"; 261 262 // Classic syntax 263 StringAssert.AreEqualIgnoringCase("hello world!", phrase); 264 265 // Constraint Syntax 266 Assert.That(phrase, Is.EqualTo("hello world!").IgnoreCase); 267 //Only available using new syntax 268 Assert.That(phrase, Is.Not.EqualTo("goodbye world!").IgnoreCase); 269 Assert.That(new string[] { "Hello", "World" }, 270 Is.EqualTo(new object[] { "HELLO", "WORLD" }).IgnoreCase); 271 Assert.That(new string[] { "HELLO", "Hello", "hello" }, 272 Is.All.EqualTo("hello").IgnoreCase); 273 274 // Inherited syntax 275 Expect(phrase, EqualTo("hello world!").IgnoreCase); 276 //Only available using new syntax 277 Expect(phrase, Not.EqualTo("goodbye world!").IgnoreCase); 278 Expect(new string[] { "Hello", "World" }, 279 EqualTo(new object[] { "HELLO", "WORLD" }).IgnoreCase); 280 Expect(new string[] { "HELLO", "Hello", "hello" }, 281 All.EqualTo("hello").IgnoreCase); 282 } 283 284 [Test] 285 public void RegularExpressionTests() 286 { 287 string phrase = "Now is the time for all good men to come to the aid of their country."; 288 string[] quotes = new string[] { "Never say never", "It's never too late", "Nevermore!" }; 289 290 // Classic syntax 291 StringAssert.IsMatch("all good men", phrase); 292 StringAssert.IsMatch("Now.*come", phrase); 293 294 // Constraint Syntax 295 Assert.That(phrase, Does.Match("all good men")); 296 Assert.That(phrase, Does.Match("Now.*come")); 297 // Only available using new syntax 298 Assert.That(phrase, Does.Not.Match("all.*men.*good")); 299 Assert.That(phrase, Does.Match("ALL").IgnoreCase); 300 Assert.That(quotes, Is.All.Matches("never").IgnoreCase); 301 302 // Inherited syntax 303 Expect(phrase, Matches("all good men")); 304 Expect(phrase, Matches("Now.*come")); 305 // Only available using new syntax 306 Expect(phrase, Not.Matches("all.*men.*good")); 307 Expect(phrase, Matches("ALL").IgnoreCase); 308 Expect(quotes, All.Matches("never").IgnoreCase); 309 } 310 #endregion 311 312 #region Equality Tests 313 [Test] 314 public void EqualityTests() 315 { 316 int[] i3 = new int[] { 1, 2, 3 }; 317 double[] d3 = new double[] { 1.0, 2.0, 3.0 }; 318 int[] iunequal = new int[] { 1, 3, 2 }; 319 320 // Classic Syntax 321 Assert.AreEqual(4, 2 + 2); 322 Assert.AreEqual(i3, d3); 323 Assert.AreNotEqual(5, 2 + 2); 324 Assert.AreNotEqual(i3, iunequal); 325 326 // Constraint Syntax 327 Assert.That(2 + 2, Is.EqualTo(4)); 328 Assert.That(2 + 2 == 4); 329 Assert.That(i3, Is.EqualTo(d3)); 330 Assert.That(2 + 2, Is.Not.EqualTo(5)); 331 Assert.That(i3, Is.Not.EqualTo(iunequal)); 332 333 // Inherited syntax 334 Expect(2 + 2, EqualTo(4)); 335 Expect(2 + 2 == 4); 336 Expect(i3, EqualTo(d3)); 337 Expect(2 + 2, Not.EqualTo(5)); 338 Expect(i3, Not.EqualTo(iunequal)); 339 } 340 341 [Test] 342 public void EqualityTestsWithTolerance() 343 { 344 // CLassic syntax 345 Assert.AreEqual(5.0d, 4.99d, 0.05d); 346 Assert.AreEqual(5.0f, 4.99f, 0.05f); 347 348 // Constraint Syntax 349 Assert.That(4.99d, Is.EqualTo(5.0d).Within(0.05d)); 350 Assert.That(4.0d, Is.Not.EqualTo(5.0d).Within(0.5d)); 351 Assert.That(4.99f, Is.EqualTo(5.0f).Within(0.05f)); 352 Assert.That(4.99m, Is.EqualTo(5.0m).Within(0.05m)); 353 Assert.That(3999999999u, Is.EqualTo(4000000000u).Within(5u)); 354 Assert.That(499, Is.EqualTo(500).Within(5)); 355 Assert.That(4999999999L, Is.EqualTo(5000000000L).Within(5L)); 356 Assert.That(5999999999ul, Is.EqualTo(6000000000ul).Within(5ul)); 357 358 // Inherited syntax 359 Expect(4.99d, EqualTo(5.0d).Within(0.05d)); 360 Expect(4.0d, Not.EqualTo(5.0d).Within(0.5d)); 361 Expect(4.99f, EqualTo(5.0f).Within(0.05f)); 362 Expect(4.99m, EqualTo(5.0m).Within(0.05m)); 363 Expect(499u, EqualTo(500u).Within(5u)); 364 Expect(499, EqualTo(500).Within(5)); 365 Expect(4999999999L, EqualTo(5000000000L).Within(5L)); 366 Expect(5999999999ul, EqualTo(6000000000ul).Within(5ul)); 367 } 368 369 [Test] 370 public void EqualityTestsWithTolerance_MixedFloatAndDouble() 371 { 372 // Bug Fix 1743844 373 Assert.That(2.20492d, Is.EqualTo(2.2d).Within(0.01f), 374 "Double actual, Double expected, Single tolerance"); 375 Assert.That(2.20492d, Is.EqualTo(2.2f).Within(0.01d), 376 "Double actual, Single expected, Double tolerance"); 377 Assert.That(2.20492d, Is.EqualTo(2.2f).Within(0.01f), 378 "Double actual, Single expected, Single tolerance"); 379 Assert.That(2.20492f, Is.EqualTo(2.2f).Within(0.01d), 380 "Single actual, Single expected, Double tolerance"); 381 Assert.That(2.20492f, Is.EqualTo(2.2d).Within(0.01d), 382 "Single actual, Double expected, Double tolerance"); 383 Assert.That(2.20492f, Is.EqualTo(2.2d).Within(0.01f), 384 "Single actual, Double expected, Single tolerance"); 385 } 386 387 [Test] 388 public void EqualityTestsWithTolerance_MixingTypesGenerally() 389 { 390 // Extending tolerance to all numeric types 391 Assert.That(202d, Is.EqualTo(200d).Within(2), 392 "Double actual, Double expected, int tolerance"); 393 Assert.That(4.87m, Is.EqualTo(5).Within(.25), 394 "Decimal actual, int expected, Double tolerance"); 395 Assert.That(4.87m, Is.EqualTo(5ul).Within(1), 396 "Decimal actual, ulong expected, int tolerance"); 397 Assert.That(487, Is.EqualTo(500).Within(25), 398 "int actual, int expected, int tolerance"); 399 Assert.That(487u, Is.EqualTo(500).Within(25), 400 "uint actual, int expected, int tolerance"); 401 Assert.That(487L, Is.EqualTo(500).Within(25), 402 "long actual, int expected, int tolerance"); 403 Assert.That(487ul, Is.EqualTo(500).Within(25), 404 "ulong actual, int expected, int tolerance"); 405 } 406 #endregion 407 408 #region Comparison Tests 409 [Test] 410 public void ComparisonTests() 411 { 412 // Classic Syntax 413 Assert.Greater(7, 3); 414 Assert.GreaterOrEqual(7, 3); 415 Assert.GreaterOrEqual(7, 7); 416 417 // Constraint Syntax 418 Assert.That(7, Is.GreaterThan(3)); 419 Assert.That(7, Is.GreaterThanOrEqualTo(3)); 420 Assert.That(7, Is.AtLeast(3)); 421 Assert.That(7, Is.GreaterThanOrEqualTo(7)); 422 Assert.That(7, Is.AtLeast(7)); 423 424 // Inherited syntax 425 Expect(7, GreaterThan(3)); 426 Expect(7, GreaterThanOrEqualTo(3)); 427 Expect(7, AtLeast(3)); 428 Expect(7, GreaterThanOrEqualTo(7)); 429 Expect(7, AtLeast(7)); 430 431 // Classic syntax 432 Assert.Less(3, 7); 433 Assert.LessOrEqual(3, 7); 434 Assert.LessOrEqual(3, 3); 435 436 // Constraint Syntax 437 Assert.That(3, Is.LessThan(7)); 438 Assert.That(3, Is.LessThanOrEqualTo(7)); 439 Assert.That(3, Is.AtMost(7)); 440 Assert.That(3, Is.LessThanOrEqualTo(3)); 441 Assert.That(3, Is.AtMost(3)); 442 443 // Inherited syntax 444 Expect(3, LessThan(7)); 445 Expect(3, LessThanOrEqualTo(7)); 446 Expect(3, AtMost(7)); 447 Expect(3, LessThanOrEqualTo(3)); 448 Expect(3, AtMost(3)); 449 } 450 #endregion 451 452 #region Collection Tests 453 [Test] 454 public void AllItemsTests() 455 { 456 object[] ints = new object[] { 1, 2, 3, 4 }; 457 object[] doubles = new object[] { 0.99, 2.1, 3.0, 4.05 }; 458 object[] strings = new object[] { "abc", "bad", "cab", "bad", "dad" }; 459 460 // Classic syntax 461 CollectionAssert.AllItemsAreNotNull(ints); 462 CollectionAssert.AllItemsAreInstancesOfType(ints, typeof(int)); 463 CollectionAssert.AllItemsAreInstancesOfType(strings, typeof(string)); 464 CollectionAssert.AllItemsAreUnique(ints); 465 466 // Constraint Syntax 467 Assert.That(ints, Is.All.Not.Null); 468 Assert.That(ints, Has.None.Null); 469 Assert.That(ints, Is.All.InstanceOf(typeof(int))); 470 Assert.That(ints, Has.All.InstanceOf(typeof(int))); 471 Assert.That(strings, Is.All.InstanceOf(typeof(string))); 472 Assert.That(strings, Has.All.InstanceOf(typeof(string))); 473 Assert.That(ints, Is.Unique); 474 // Only available using new syntax 475 Assert.That(strings, Is.Not.Unique); 476 Assert.That(ints, Is.All.GreaterThan(0)); 477 Assert.That(ints, Has.All.GreaterThan(0)); 478 Assert.That(ints, Has.None.LessThanOrEqualTo(0)); 479 Assert.That(strings, Is.All.Contains("a")); 480 Assert.That(strings, Has.All.Contains("a")); 481 Assert.That(strings, Has.Some.StartsWith("ba")); 482 Assert.That(strings, Has.Some.Property("Length").EqualTo(3)); 483 Assert.That(strings, Has.Some.StartsWith("BA").IgnoreCase); 484 Assert.That(doubles, Has.Some.EqualTo(1.0).Within(.05)); 485 486 // Inherited syntax 487 Expect(ints, All.Not.Null); 488 Expect(ints, None.Null); 489 Expect(ints, All.InstanceOf(typeof(int))); 490 Expect(strings, All.InstanceOf(typeof(string))); 491 Expect(ints, Unique); 492 // Only available using new syntax 493 Expect(strings, Not.Unique); 494 Expect(ints, All.GreaterThan(0)); 495 Expect(ints, None.LessThanOrEqualTo(0)); 496 Expect(strings, All.Contains("a")); 497 Expect(strings, Some.StartsWith("ba")); 498 Expect(strings, Some.StartsWith("BA").IgnoreCase); 499 Expect(doubles, Some.EqualTo(1.0).Within(.05)); 500 } 501 502 [Test] 503 public void SomeItemTests() 504 { 505 object[] mixed = new object[] { 1, 2, "3", null, "four", 100 }; 506 object[] strings = new object[] { "abc", "bad", "cab", "bad", "dad" }; 507 508 // Not available using the classic syntax 509 510 // Constraint Syntax 511 Assert.That(mixed, Has.Some.Null); 512 Assert.That(mixed, Has.Some.InstanceOf(typeof(int))); 513 Assert.That(mixed, Has.Some.InstanceOf(typeof(string))); 514 Assert.That(strings, Has.Some.StartsWith("ba")); 515 Assert.That(strings, Has.Some.Not.StartsWith("ba")); 516 517 // Inherited syntax 518 Expect(mixed, Some.Null); 519 Expect(mixed, Some.InstanceOf(typeof(int))); 520 Expect(mixed, Some.InstanceOf(typeof(string))); 521 Expect(strings, Some.StartsWith("ba")); 522 Expect(strings, Some.Not.StartsWith("ba")); 523 } 524 525 [Test] 526 public void NoItemTests() 527 { 528 object[] ints = new object[] { 1, 2, 3, 4, 5 }; 529 object[] strings = new object[] { "abc", "bad", "cab", "bad", "dad" }; 530 531 // Not available using the classic syntax 532 533 // Constraint Syntax 534 Assert.That(ints, Has.None.Null); 535 Assert.That(ints, Has.None.InstanceOf(typeof(string))); 536 Assert.That(ints, Has.None.GreaterThan(99)); 537 Assert.That(strings, Has.None.StartsWith("qu")); 538 539 // Inherited syntax 540 Expect(ints, None.Null); 541 Expect(ints, None.InstanceOf(typeof(string))); 542 Expect(ints, None.GreaterThan(99)); 543 Expect(strings, None.StartsWith("qu")); 544 } 545 546 [Test] 547 public void CollectionContainsTests() 548 { 549 int[] iarray = new int[] { 1, 2, 3 }; 550 string[] sarray = new string[] { "a", "b", "c" }; 551 552 // Classic syntax 553 Assert.Contains(3, iarray); 554 Assert.Contains("b", sarray); 555 CollectionAssert.Contains(iarray, 3); 556 CollectionAssert.Contains(sarray, "b"); 557 CollectionAssert.DoesNotContain(sarray, "x"); 558 // Showing that Contains uses NUnit equality 559 CollectionAssert.Contains(iarray, 1.0d); 560 561 // Constraint Syntax 562 Assert.That(iarray, Has.Member(3)); 563 Assert.That(sarray, Has.Member("b")); 564 Assert.That(sarray, Has.No.Member("x")); 565 // Showing that Contains uses NUnit equality 566 Assert.That(iarray, Has.Member(1.0d)); 567 568 // Only available using the new syntax 569 // Note that EqualTo and SameAs do NOT give 570 // identical results to Contains because 571 // Contains uses Object.Equals() 572 Assert.That(iarray, Has.Some.EqualTo(3)); 573 Assert.That(iarray, Has.Member(3)); 574 Assert.That(sarray, Has.Some.EqualTo("b")); 575 Assert.That(sarray, Has.None.EqualTo("x")); 576 Assert.That(iarray, Has.None.SameAs(1.0d)); 577 Assert.That(iarray, Has.All.LessThan(10)); 578 Assert.That(sarray, Has.All.Length.EqualTo(1)); 579 Assert.That(sarray, Has.None.Property("Length").GreaterThan(3)); 580 581 // Inherited syntax 582 Expect(iarray, Contains(3)); 583 Expect(sarray, Contains("b")); 584 Expect(sarray, Not.Contains("x")); 585 586 // Only available using new syntax 587 // Note that EqualTo and SameAs do NOT give 588 // identical results to Contains because 589 // Contains uses Object.Equals() 590 Expect(iarray, Some.EqualTo(3)); 591 Expect(sarray, Some.EqualTo("b")); 592 Expect(sarray, None.EqualTo("x")); 593 Expect(iarray, All.LessThan(10)); 594 Expect(sarray, All.Length.EqualTo(1)); 595 Expect(sarray, None.Property("Length").GreaterThan(3)); 596 } 597 598 [Test] 599 public void CollectionEquivalenceTests() 600 { 601 int[] ints1to5 = new int[] { 1, 2, 3, 4, 5 }; 602 int[] twothrees = new int[] { 1, 2, 3, 3, 4, 5 }; 603 int[] twofours = new int[] { 1, 2, 3, 4, 4, 5 }; 604 605 // Classic syntax 606 CollectionAssert.AreEquivalent(new int[] { 2, 1, 4, 3, 5 }, ints1to5); 607 CollectionAssert.AreNotEquivalent(new int[] { 2, 2, 4, 3, 5 }, ints1to5); 608 CollectionAssert.AreNotEquivalent(new int[] { 2, 4, 3, 5 }, ints1to5); 609 CollectionAssert.AreNotEquivalent(new int[] { 2, 2, 1, 1, 4, 3, 5 }, ints1to5); 610 CollectionAssert.AreNotEquivalent(twothrees, twofours); 611 612 // Constraint Syntax 613 Assert.That(new int[] { 2, 1, 4, 3, 5 }, Is.EquivalentTo(ints1to5)); 614 Assert.That(new int[] { 2, 2, 4, 3, 5 }, Is.Not.EquivalentTo(ints1to5)); 615 Assert.That(new int[] { 2, 4, 3, 5 }, Is.Not.EquivalentTo(ints1to5)); 616 Assert.That(new int[] { 2, 2, 1, 1, 4, 3, 5 }, Is.Not.EquivalentTo(ints1to5)); 617 618 // Inherited syntax 619 Expect(new int[] { 2, 1, 4, 3, 5 }, EquivalentTo(ints1to5)); 620 Expect(new int[] { 2, 2, 4, 3, 5 }, Not.EquivalentTo(ints1to5)); 621 Expect(new int[] { 2, 4, 3, 5 }, Not.EquivalentTo(ints1to5)); 622 Expect(new int[] { 2, 2, 1, 1, 4, 3, 5 }, Not.EquivalentTo(ints1to5)); 623 } 624 625 [Test] 626 public void SubsetTests() 627 { 628 int[] ints1to5 = new int[] { 1, 2, 3, 4, 5 }; 629 630 // Classic syntax 631 CollectionAssert.IsSubsetOf(new int[] { 1, 3, 5 }, ints1to5); 632 CollectionAssert.IsSubsetOf(new int[] { 1, 2, 3, 4, 5 }, ints1to5); 633 CollectionAssert.IsNotSubsetOf(new int[] { 2, 4, 6 }, ints1to5); 634 CollectionAssert.IsNotSubsetOf(new int[] { 1, 2, 2, 2, 5 }, ints1to5); 635 636 // Constraint Syntax 637 Assert.That(new int[] { 1, 3, 5 }, Is.SubsetOf(ints1to5)); 638 Assert.That(new int[] { 1, 2, 3, 4, 5 }, Is.SubsetOf(ints1to5)); 639 Assert.That(new int[] { 2, 4, 6 }, Is.Not.SubsetOf(ints1to5)); 640 641 // Inherited syntax 642 Expect(new int[] { 1, 3, 5 }, SubsetOf(ints1to5)); 643 Expect(new int[] { 1, 2, 3, 4, 5 }, SubsetOf(ints1to5)); 644 Expect(new int[] { 2, 4, 6 }, Not.SubsetOf(ints1to5)); 645 } 646 #endregion 647 648 #region Property Tests 649 [Test] 650 public void PropertyTests() 651 { 652 string[] array = { "abc", "bca", "xyz", "qrs" }; 653 string[] array2 = { "a", "ab", "abc" }; 654 ArrayList list = new ArrayList(array); 655 656 // Not available using the classic syntax 657 658 // Constraint Syntax 659 Assert.That(list, Has.Property("Count")); 660 Assert.That(list, Has.No.Property("Length")); 661 662 Assert.That("Hello", Has.Length.EqualTo(5)); 663 Assert.That("Hello", Has.Length.LessThan(10)); 664 Assert.That("Hello", Has.Property("Length").EqualTo(5)); 665 Assert.That("Hello", Has.Property("Length").GreaterThan(3)); 666 667 Assert.That(array, Has.Property("Length").EqualTo(4)); 668 Assert.That(array, Has.Length.EqualTo(4)); 669 Assert.That(array, Has.Property("Length").LessThan(10)); 670 671 Assert.That(array, Has.All.Property("Length").EqualTo(3)); 672 Assert.That(array, Has.All.Length.EqualTo(3)); 673 Assert.That(array, Is.All.Length.EqualTo(3)); 674 Assert.That(array, Has.All.Property("Length").EqualTo(3)); 675 Assert.That(array, Is.All.Property("Length").EqualTo(3)); 676 677 Assert.That(array2, Has.Some.Property("Length").EqualTo(2)); 678 Assert.That(array2, Has.Some.Length.EqualTo(2)); 679 Assert.That(array2, Has.Some.Property("Length").GreaterThan(2)); 680 681 Assert.That(array2, Is.Not.Property("Length").EqualTo(4)); 682 Assert.That(array2, Is.Not.Length.EqualTo(4)); 683 Assert.That(array2, Has.No.Property("Length").GreaterThan(3)); 684 685 Assert.That(List.Map(array2).Property("Length"), Is.EqualTo(new int[] { 1, 2, 3 })); 686 Assert.That(List.Map(array2).Property("Length"), Is.EquivalentTo(new int[] { 3, 2, 1 })); 687 Assert.That(List.Map(array2).Property("Length"), Is.SubsetOf(new int[] { 1, 2, 3, 4, 5 })); 688 Assert.That(List.Map(array2).Property("Length"), Is.Unique); 689 690 Assert.That(list, Has.Count.EqualTo(4)); 691 692 // Inherited syntax 693 Expect(list, Property("Count")); 694 Expect(list, Not.Property("Nada")); 695 696 Expect("Hello", Length.EqualTo(5)); 697 Expect("Hello", Property("Length").EqualTo(5)); 698 Expect("Hello", Property("Length").GreaterThan(0)); 699 700 Expect(array, Property("Length").EqualTo(4)); 701 Expect(array, Length.EqualTo(4)); 702 Expect(array, Property("Length").LessThan(10)); 703 704 Expect(array, All.Length.EqualTo(3)); 705 Expect(array, All.Property("Length").EqualTo(3)); 706 707 Expect(array2, Some.Property("Length").EqualTo(2)); 708 Expect(array2, Some.Length.EqualTo(2)); 709 Expect(array2, Some.Property("Length").GreaterThan(2)); 710 711 Expect(array2, None.Property("Length").EqualTo(4)); 712 Expect(array2, None.Length.EqualTo(4)); 713 Expect(array2, None.Property("Length").GreaterThan(3)); 714 715 Expect(Map(array2).Property("Length"), EqualTo(new int[] { 1, 2, 3 })); 716 Expect(Map(array2).Property("Length"), EquivalentTo(new int[] { 3, 2, 1 })); 717 Expect(Map(array2).Property("Length"), SubsetOf(new int[] { 1, 2, 3, 4, 5 })); 718 Expect(Map(array2).Property("Length"), Unique); 719 720 Expect(list, Count.EqualTo(4)); 721 722 } 723 #endregion 724 725 #region Not Tests 726 [Test] 727 public void NotTests() 728 { 729 // Not available using the classic syntax 730 731 // Constraint Syntax 732 Assert.That(42, Is.Not.Null); 733 Assert.That(42, Is.Not.True); 734 Assert.That(42, Is.Not.False); 735 Assert.That(2.5, Is.Not.NaN); 736 Assert.That(2 + 2, Is.Not.EqualTo(3)); 737 Assert.That(2 + 2, Is.Not.Not.EqualTo(4)); 738 Assert.That(2 + 2, Is.Not.Not.Not.EqualTo(5)); 739 740 // Inherited syntax 741 Expect(42, Not.Null); 742 Expect(42, Not.True); 743 Expect(42, Not.False); 744 Expect(2.5, Not.NaN); 745 Expect(2 + 2, Not.EqualTo(3)); 746 Expect(2 + 2, Not.Not.EqualTo(4)); 747 Expect(2 + 2, Not.Not.Not.EqualTo(5)); 748 } 749 #endregion 750 751 #region Operator Tests 752 [Test] 753 public void NotOperator() 754 { 755 // The ! operator is only available in the new syntax 756 Assert.That(42, !Is.Null); 757 // Inherited syntax 758 Expect(42, !Null); 759 } 760 761 [Test] 762 public void AndOperator() 763 { 764 // The & operator is only available in the new syntax 765 Assert.That(7, Is.GreaterThan(5) & Is.LessThan(10)); 766 // Inherited syntax 767 Expect(7, GreaterThan(5) & LessThan(10)); 768 } 769 770 [Test] 771 public void OrOperator() 772 { 773 // The | operator is only available in the new syntax 774 Assert.That(3, Is.LessThan(5) | Is.GreaterThan(10)); 775 Expect(3, LessThan(5) | GreaterThan(10)); 776 } 777 778 [Test] 779 public void ComplexTests() 780 { 781 Assert.That(7, Is.Not.Null & Is.Not.LessThan(5) & Is.Not.GreaterThan(10)); 782 Expect(7, Not.Null & Not.LessThan(5) & Not.GreaterThan(10)); 783 784 Assert.That(7, !Is.Null & !Is.LessThan(5) & !Is.GreaterThan(10)); 785 Expect(7, !Null & !LessThan(5) & !GreaterThan(10)); 786 787 // No longer works at all under 3.0 788 // TODO: Evaluate why we wanted to use null in this setting in the first place 789 #if false 790 // TODO: Remove #if when mono compiler can handle null 791 #if MONO 792 Constraint x = null; 793 Assert.That(7, !x & !Is.LessThan(5) & !Is.GreaterThan(10)); 794 Expect(7, !x & !LessThan(5) & !GreaterThan(10)); 795 #else 796 Assert.That(7, !(Constraint)null & !Is.LessThan(5) & !Is.GreaterThan(10)); 797 Expect(7, !(Constraint)null & !LessThan(5) & !GreaterThan(10)); 798 #endif 799 #endif 800 } 801 #endregion 802 803 #region Invalid Code Tests 804 // This method contains assertions that should not compile 805 // You can check by uncommenting it. 806 //public void WillNotCompile() 807 //{ 808 // Assert.That(42, Is.Not); 809 // Assert.That(42, Is.All); 810 // Assert.That(42, Is.Null.Not); 811 // Assert.That(42, Is.Not.Null.GreaterThan(10)); 812 // Assert.That(42, Is.GreaterThan(10).LessThan(99)); 813 814 // object[] c = new object[0]; 815 // Assert.That(c, Is.Null.All); 816 // Assert.That(c, Is.Not.All); 817 // Assert.That(c, Is.All.Not); 818 //} 819 #endregion 820 } 821 822 #endregion