走進 .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
單元測試參考資料
文章列表