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 }