【学习笔记】C#中的单元测试
周一老师讲完单元测试以后,感觉挺好玩,通过查资料和相关书籍学到了几种C#在VS2010的测试方法,跟大家分享下,图文并茂啊,有木有~~
1.从被测试的代码中生成单元测试
1.1创建C#控制台程序,命名为AddUnitText
1.2然后先用一小段很简单的代码练习一下
1 class Program 2 { 3 public int Add(int a, int b) 4 { 5 return a + b; 6 } 7 static void Main(string[] args) 8 { 9 } 10 }
1.3然后用下面的步骤创建单元测试
(1)在Add方法体中,在右击菜单中选择创建单元测试,并为这个方法创建单元测试代码的基本框架
(2)点击确定后,系统自动生成单元测试代码,如下所示
1 namespace AddText 2 { 3 /// <summary> 4 ///这是 ProgramTest 的测试类,旨在 5 ///包含所有 ProgramTest 单元测试 6 ///</summary> 7 [TestClass()] 8 public class ProgramTest 9 { 10 11 12 private TestContext testContextInstance; 13 14 /// <summary> 15 ///获取或设置测试上下文,上下文提供 16 ///有关当前测试运行及其功能的信息。 17 ///</summary> 18 public TestContext TestContext 19 { 20 get 21 { 22 return testContextInstance; 23 } 24 set 25 { 26 testContextInstance = value; 27 } 28 } 29 30 #region 附加测试特性 31 // 32 //编写测试时,还可使用以下特性: 33 // 34 //使用 ClassInitialize 在运行类中的第一个测试前先运行代码 35 //[ClassInitialize()] 36 //public static void MyClassInitialize(TestContext testContext) 37 //{ 38 //} 39 // 40 //使用 ClassCleanup 在运行完类中的所有测试后再运行代码 41 //[ClassCleanup()] 42 //public static void MyClassCleanup() 43 //{ 44 //} 45 // 46 //使用 TestInitialize 在运行每个测试前先运行代码 47 //[TestInitialize()] 48 //public void MyTestInitialize() 49 //{ 50 //} 51 // 52 //使用 TestCleanup 在运行完每个测试后运行代码 53 //[TestCleanup()] 54 //public void MyTestCleanup() 55 //{ 56 //} 57 // 58 #endregion 59 60 61 /// <summary> 62 ///Add 的测试 63 ///</summary> 64 [TestMethod()] 65 public void AddTest() 66 { 67 Program target = new Program(); // TODO: 初始化为适当的值 68 int a = 0; // TODO: 初始化为适当的值 69 int b = 0; // TODO: 初始化为适当的值 70 int expected = 0; // TODO: 初始化为适当的值 71 int actual; 72 actual = target.Add(a, b); 73 Assert.AreEqual(expected, actual); 74 Assert.Inconclusive("验证此测试方法的正确性。"); 75 } 76 } 77 }
(3)ProgramTest.cs代码文件详讲
[TestMethod()]:说明了以下代码是一个测试用例
Int a = o; // TODO: 初始化为适当的值
int b = 0; // TODO: 初始化为适当的值
这两句是被测函数的输入参数,需要我们去修改它的值,也就是我们输入测试用例的地方。
double expected = 0; // TODO: 初始化为适当的值
double actual;
这两句话浅显易懂,前一句话是定义了期望值和对它进行初始化,后一句话是定义了实际值。默认
Assert.AreEqual(expected, actual);
Assert在这里可以理解成断言:在VSTS里做单元测试是基于断言的测试。
默认代码中Assert.Inconclusive 表明这是一个未经验证的单元测试。在实际的程序中可以注释掉。
(4)还可以在C#项目中自行创建单元测试项目,然后编写测试方法
单元测试的基本方法是调用被测代码的函数,输入函数的参数值,获取返回结果,然后与预期测试结果进行比较,如果相等则认为测试通过,否则认为测试不通过。
1、Assert类的使用
Assert.Inconclusive() 表示一个未验证的测试;
Assert.AreEqual() 测试指定的值是否相等,如果相等,则测试通过;
AreSame() 用于验证指定的两个对象变量是指向相同的对象,否则认为是错误
AreNotSame() 用于验证指定的两个对象变量是指向不同的对象,否则认为是错误
Assert.IsTrue() 测试指定的条件是否为True,如果为True,则测试通过;
Assert.IsFalse() 测试指定的条件是否为False,如果为False,则测试通过;
Assert.IsNull() 测试指定的对象是否为空引用,如果为空,则测试通过;
Assert.IsNotNull() 测试指定的对象是否为非空,如果不为空,则测试通过;
2、CollectionAssert类的使用
用于验证对象集合是否满足条件
StringAssert类的使用
用于比较字符串。
StringAssert.Contains
StringAssert.Matches
StringAssert.tartWith
3、附加测试属性的使用
默认都是被注释掉的,只要我们取消注释就可以使用了。这个功能的加入,很大程度上是为了增加测试的灵活性。具体的属性有:
[ClassInitialize()]在运行类的第一个测试前先运行代码
[ClassCleanup()]在运行完类中的所有测试后再运行代码
[TestInitialize()]在运行每个测试前先运行代码
[TestCleanup()]在运行完每个测试后运行代码
4、测试单元NUnit 声明
1.AreEqual
Assert.AreEqual(expected,actual[,string message])
//判断结果与预期是否相等
报告的结果如下:
Assert.AreEqia;(expected,actual,tolerance[,string message])
2.IsNull
Assert.IsNull(object [, string message])
Assert.IsNotNull(object [, string message])
声明给的对象是否属于空
3.AreSame
Assert.AreSame(expected, actual [, string message])
声明是否同类型
4.IsTrue
Assert.IsTrue(bool condition [, string message])
判断返回条件是否为真
5.Fail
Assert.Fail([string message])
测试立即失败。
2.下面是老师课上编写的程序
2.1这是测试代码:
查找list[]中的最大值:int Largest(int list[], int length);
首份实现代码如下:
int Largest(int list[], int length)
{
int i,max;
for(i = 0; i < (length – 1); i ++ )
{
if(list[i] > max)
{ max=list[i]; }
}
return max;
}
2.2编写程序:
1 static void Main(string[] args) 2 { 3 int[] List = new int[3];//申明一个长度为3的数组保存录入的3个数 4 int Max = 0;//保存最大值 5 for (int i = 0; i < List.Length; i++)//循环数组 6 { 7 Console.WriteLine("请输入第" + (i + 1) + "个数:"); 8 List[i] = int.Parse(Console.ReadLine());//循环将录入的数字保存到数组 9 if (List[i] > Max)//判断当前数字是否大于最大值 10 { 11 Max = List[i];//将最大值赋值给Max 12 } 13 } 14 Console.WriteLine("最大的数是:{0}",Max);//输出最大值 15 Console.ReadLine(); 16 }
2.3在此测试的过程中发现无法对程序进行有效的测试,所以重新写了方法
1 namespace MUnitText 2 { 3 public class LIU 4 { 5 /// <summary> 6 /// 把返回的最大值放在list中 7 /// </summary> 8 /// <param name="list">一列整数</param> 9 /// <returns>最大值返回给出的list中</returns> 10 public static int Largest(int[] list) 11 { 12 int i, max = Int32.MaxValue; 13 for (i = 0; i < list.Length - 1; i++) 14 { 15 if (list[i] > max) 16 { 17 max = list[i]; 18 } 19 } 20 return max; 21 } 22 } 23 }
2.4创建单元测试
测试了多组数据以后,验证了老师上课提到的那些错误。
给一列数字[7,8,9].这个方法返回9.这是很符合常理的一个测试用例。但是,另外的测试用例如何想?
要写多少测试用例?
下面给出测试思想。
[7,8,9]—>9
[8,9,7]—>9
[9,7,8]—>9
当有重复的最大的数字时候将会发生什么?
[7,9,8,9]—>9
因为只存在int类型,没有objects类型,所以你可能不会关系9返回的是什么类型。
那么当只有1个数字的时候,它将会是什么?
[1]—>1
并且当出现负数时候又会发生什么情况:
[-9,-8,-7]—>-7
可以很很简单的看出来-7比-9大。
2.5编写测试方法
首先:通过Globally assembly cath调用using NUnit.Framework;
NUnit框架提供我们需要的单元测试的功能。
下一步,我们要定义一个类:每一个类包含着测试用例状态属性的注释。必须被声明为共有的,它必须有一个共有的,没有参数和构造器的。
最终,这个测试类包含单个带有测试属性的测试方法。
1 using NUnit.Framework; 2 3 [TestFixture] 4 5 public class TestSimple{ 6 7 [Test] 8 9 public void LargestOf3(){ 10 11 Assert.AreEqual(9,Cmp.Largest(new int[]{8,9,7})); 12 13 Assert.AreEqual(100,Cmp.Largest(new int[]{100,4,25})); 14 15 Assert.AreEqual(64,Cmp.Largest(new int[]{1,64,38})); 16 17 } 18 19 }
测试了一上午,太不容易了,抓紧搞电梯了。。