系列目录html
在开始本篇以前须要补充一些内容,经过前面搭建Nunit测试环境咱们知道要使一个方法成为单元测试方法首先要在此方法所在类加上TestFixture注解,而且在该方法上添加上Test注解.
然而还有一点须要注意:全部进行单元测试的方法必须标识为public访问级别,不然没法识别为单元测试方法数组
此外,单元测试方法还有如下特征sass
单元测试方法不能带有参数
这里说的不能是指不能像普通方法同样带有普通的参数(能够带基于注解的特殊参数)
若是像普通方法同样带参数,虽然编译能经过,可是运行时会抛出异常.less
单元测试方法不能重载
这里说的不能是不该该,实践中是能够的,可是重载方法会带来无尽的麻烦,读者能够本身实践一下.
进行单元测试无非就是对不一样参数引发方法出现不一样结果的断言(通常状况下全部的单元测试方法都有断言)下面咱们来看Nunit中最基本最经常使用的断言异步
Assert.True用于断言布尔参数是否为true
Assert.True的重载方法还支持可空布尔参数单元测试
Assert.True还支持自定义错误提示
上面代码改成以下测试
若是返回错误的时候,咱们自定义的错误信息就会显示出来.3d
其它的断言方法也大都有此重载代码规范
此断言方法为Assert.True的亲兄弟,两者功能如出一辙.code
与Assert.True断言状态相反,断言某一参数的结果为false
这里须要特别说明的是,单元测试应该力求简单,明了,断言尤为如此.
上面的断言还也能够写成
Assert.False(!firstCondition);
这和断言变量firstCondition为true最终功能同样,可是看上去很不直接明了,一般状况下我见到Assert.False第一反应就是断言一个变量为False,这里则反其道行之,其实是断言一个变量为true,这种状况应当避免.
Assert.False的亲兄弟,两者表现如出一辙
Nunit Assert类还有还多其它的前面带有Is的方法,它们都和不带Is的如出一辙,其中带Is的是为了兼容老版本写法.
用于断言一个变量是否为null,这里再也不举例,可是实际中用的却比较多.
用于断言一个变量不是null,它和Assert.Null()功能相同,只是断言的状态相反.
Nunit里还有其它的前缀有Not的方法,它和不带Not的方法用法同样,只是断言的状态相反
Assert.Throws
用于断言特定方法在运行的时候会抛出异常.此方法有泛型版本,异步版本,这里仅对异步版本进行说明
因为示例愈来愈复制,咱们不能只在测试方法内写一些简单代码进行测试了,这里咱们新建一个Person类以下
这个类里面包含一个WhetherNameContainsB方法,用于判断实例的Name是否包含字母B,
这个方法里面有三个逻辑分支,单元测试的时候每个都要覆盖到,这里咱们断言若是name为null则抛出ArgumentNullException
咱们编写以下单元测试方法
运行这个测试,则会返回成功状态,由于预期的异常出现了.
用于断言字段串是否为空字符串.
用于断言数字类型(int,long,float,double,decimal等)为正数(大于零的数)
其实不少断言均可以断言均可以用Assert.True来完成,好比断言一个数是否为正数,能够用Assert.True(a>0),这里因为a只是一个普通变量,使用a>0做为条件主义仍然十分清析,然而到了后面有咱们不只要判断一个变通变量,还要判断lambda表达式,若是条件过于复杂,则语义会变得不是特别清析了,使用Assert自带的静态方法主义会更加清析,可读性更高.
用于断言数字类型为负数(小于零,不包括零)
用于断言数字类型为数字零
用于断言数字类型不是零.
不少时候,Not包含的范围很是广,进行单元测试是为了在开发阶段找出问题,解决问题,所以断言的范围越窄越好,咱们不能仅仅让单元测试经过了事.
好比一个方法返回的结果是数字类型,咱们要判定它是正数?大于某一个数的正数?在必定范围的正数?是一个具体的正数?而不能简单的是零,不是零.固然这还要根据业务自己来确实,有些时候范围可能确实很大,可是必定要注意单元测试原则.
用于断言数字类型的变量大于(或者等于)某一个值
用于断言数字类型小于(或者等于)某一值
用于断言集合中是否包含某一元素.
好比如下方法,用于断言字符串数组中是否包含特定字符串
用于断言两个对象是否相等
这个静态方法并无提供重载参数用于指定一个比较器来比较引用对象的相等性,须要实现equals和gethashcode方法才能获得预期结果,但在实际中咱们每每把比较器放在类外边,如何在比较引用对象的时候加载一个比较器在后面章节会有介绍,这里先略过.
上面一篇咱们讲解了一些基本断言,利用这些断言咱们就能够进行单元测试了,然而仅仅使用简单断言仍是不够的,若是逻辑复杂度较高,使用简单的断言会致使单元测试代码量增长,最终致使单元测试自己过于复杂和难以维护.须要说明的是这里所说的复杂断言仍然在Assert的静态方法里面,自己也不是特别复杂,只是比前面讲的秒复杂一些,只是若是没有了这些方法,一些特殊功能实现起来比较费劲基本没法实现.
下面就介绍一下这些方法.
Assert.Catch有泛型和异步方法,这里只介绍其泛型方法.不少即便常用单元测试功能的人也未必用过这个方法.
其实这个方法和Assert.Throw用法上相似,只是有一点不一样的是要测试的方法里的异常能够是catch到的异常的子类,实际开发中,若是咱们能确立异常的类型,则最好捕获具体类型异常,然而不能排除有一些不够规范的代码整段代码被一个try catch包围,这时候不必定可以捕获到想要的特定异常,这时候可使用Assert.Catch
以上代码相似上一节中讲throw时使用的代码,只是这里泛型参数里是Exception而不是具体的异常信息,咱们运行这段代码,依然可以测试经过.
在单元测试中,期待的状态越具体越好,然而因为种种缘由(好比立项时候没有对代码规范作过多要求,开发者水平不高,要测试的代码是别人写的,写单元测试的人对其中逻辑并非特别清楚等)咱们没法作到很是具体,这个时候能够把要得到的状态放宽之后,待条件完备了再修改单元测试以进一步收窄状态.
Assert.Ignore和Ignore注解功能相似,能够在测试的时候忽略一个单元测试.有些状况下咱们须要暂时忽略一个测试,好比说要进行测试的内容有一个外部依赖,如今外部依赖暂时不可用,若是咱们不忽略的话测试将会失败,在自动化环境下,失败将致使没法进行下一步动做,此时咱们能够暂时忽略这个测试.
忽略的测试前面有一个 黄色叹号标志,警示咱们须要注意.
咱们先看一下面一段代码
在这个单元测试自己使用到了try catch,咱们知道WhetherNameContainsB方法在Person类的Name没有提供值的状况下会抛出异常,然而咱们的代码并无断言这个异常存在,此时因为catch代码块存在,会把异常吞掉,所以最终咱们断言person的Age为正数的时候将会经过(咱们在构造类的时候设置了Age为32)
这显然不行的,这时候我把们Assert.Fail(e.Message)取消注释,测试便会变成失败状态.
用于断言一个Double类型数字是不是NaN
虽然实际业务中咱们并不会写以上代码,可是若是除数和被除数是经过复杂计算得来的则有可能除数和被除数都是零.
用于断言一个对象是不是指定类型的实例,
如上psn是Person类的一个实例,而Person继承自Object,所以psn也是Object类的实例
此方法和以上方法做用相反,它用来断言指定类型是当前对象类型的子类.(Assert.IsInstanceOf判断的是当前对象是指定类型的子类)
这个方法语义不是很明确,很容易搞晕,使用的时候须要特别注意
用于使一个测试经过,可是出现警示信息.