.netcore持续集成测试篇之开篇简介及Xunit基本使用

系列目录html

为了支持跨平台,微软为.net平台提供了.net core test sdk,这样第三方测试框架诸如Nunit,Xunit等只须要按照sdk提供的api规范进行开发即可以被dotnet cli工具调用,这样就解决了在持续集成过程当中第三方框架依赖于windows平台上的各自runner的问题,使得测试框架开发者不须要花费很大功夫就能够快速迁移到.net core平台,同时封装了各测试框架的实现细节,对外暴露统一调用接口,大大减小devops开发者的工做量.web

做为单元测试基础知识介绍,这里只介绍经常使用单元测试框架Nunit和Xunit如何在.net core平台上使用,并介绍因为.net core的变化所引发的须要注意的测试代码的相应改变,对于如何在Jenkins环境中自动完成测试的相关内容Jenkins基础知识里面介绍正则表达式

考虑到实际工做中可能有的项目组已经使用或者尝试使用xunit,而且.net core对xunit支持较好,诸多开源项目的单元测试也都使用的是Xunit,本章节做为补充对Xunit基础知识进行讲解,以帮助还不太了解这个框架的同窗快速入门.windows

咱们知道在.net framework下相要对mvc项目进行集成测试很是困难,一方面.net http管道里有不少黑盒子,开发者对它的实现细节一无所知,两者须要mock的对象太多,工做量巨大.所以很难在持续集成环境中对web项目进行集成测试.开发者或者测试人员大都依赖postman,fiddler,以及浏览器的http请求插件来进行集成测试,这样带来的一个很大问题这些http请求很难复用,更难以有效的组织管理.即便使用postman这样强大的http工具若是测试接口过多代码也会变得一塌糊涂,过一段时间后想要知道哪一个方法是测试哪一个接口用的就须要经过搜索来导航到指定的测试方法,而且不少时候有于各模块有相同名称的方法,每每须要先找到方法所在的area,而后再找到controller而后再找到相应方法...若是出现问题的代码过多每每把开发者搞的焦头烂额,苦不堪言.
幸运的是在.net core里很容易模拟一个httpt管道,这一方面使得集成测试在持续集成环境中使用提供了可能,另外一方http请求写成程序里,能够很方便的导航到指定的测试方法,极大提供可维护性.本章节最后会介绍如何搭建一个.net core web项目的selfhost环境以供在单元测试框架中使用.api

下面咱们将简要介绍如何在vs中配置xunt环境以及Xunit断言的基本使用浏览器

.net core 中使用Xunit

Xunit是.net平台下的一款单元测试工具,相似Nunit.可是更为轻量,更加专一于单元测试而不像Nunit提供了不少额外的功能sass

.net core对Xunit支持较好,VisualStudio 2017提供有一个Xunit单元测试模板能够很方便的建立一个Xunit单元测试项目.mvc

avatar
如图,在visual studio里建立项目时,选择.net core项目,而后从模板里面找到Xunit单元测试项目即可以建立一个Xunit单元测试项目了.框架

咱们打开刚建立的项目右键选择"Nuget包管理",从包管理工具里咱们能够看到,实际上这个模板引用了xunit,和xunit.runner.visualstudio这两个包.这样,咱们也能够本身手动建立一个.net core类型的库文件,而后引入这两个包,能达到一样的效果.工具

这里建议你们经过模板来建立单元测试项目,由于单元测试框架不一样版本可能须要引用不一样的包,没有经验的同窗经常因为引用的包不对致使单元测试项目跑不起来,搞得灰头土脸,很是郁闷.

咱们编写如下单元测试代码

public class UnitTest1
    {
        [Fact]
        public void Test1()
        {
            int intt = 3 + 2;
            Assert.True(intt==5);
        }
    }

经过以上代码咱们看到Xunit就测试断言和Nunit很相似(这里指Nunit3,早期版本Nunit差别较大,建议大这在工做中也尽可能选用Nunit3,而不是1或者2)

这里有一点差别须要指出,Xunit并不须要对单元测试类进行注解(Nunit是须要的,不然没法识别),只须要在须要测试的方法上加上fact注解便可.

单元测试方法的运行也和前面讲的Nunit单元测试运行方法相同,这里再也不赘述.

常见基本断言

虽然Xunit和Nunit在断言上有不少类似的地方,而且有愈来愈像的趋势,可是仍然有很多差异,所以这里仍然会对Xunit的断言功能进行一个全面的列举,以供你们速查.而且有时候会指出它和Nunit的差异或者指出Nunit中比较难以实现或者技巧性很强的功能如何在Xunit里实现.若是有读者直接阅读本章节而没有了解过Nunit,能够有选择的略过两者比较的内容.

这里首先指出一个很大的差异.Xunit里并无像Nunit里的stringAssertion,FileAssertion和CollectionAssertion,而是全部的断言都在Assert静态类里,方法也不是不少,语义也相对更加明确,很适应没有单元测试基础的同窗快速入门.

下面开始介绍Xunit里的断言方法

Assert.Null

用于断言一个对象是不是Null

这个方法有一个相对含义的断言就是Assert.NotNull,不少其它的方法也有带Not的断言,很容易理解.

Assert. Assert.Equal

此方法有不少重载,用于比较两个字符串,int,decimal或者对象类型是否相等.

注意这里比较两个对象是否相等时,至关于Object.equals()来比较两个对象是否相等

这个方法用于比较两个double类型值是否相等时,能够指定精度.

Assert.StrictEqual

从字面上来看,它用于比较两个对象是不是严格相等,然而它的表现行为和以上Equal方法很是相似,并非比较两个对象内存地址是否相等.实际上它是在比较的时候指定一个默认的比较器.这个方法着实很是让人困惑.

Assert.same

用于比较两个对象运行是是否指定同一块内存地址,若是要比较两个对象是否彻底相等,则使用它.

注意,虽然Assert.same接收的是两个object类型对象,可是不建议用它来比较简单类型,它实际上是用于比较两个对象是否指向同一内存地址,所以只有比较引用对象才是有意义的.这个方法应该设计成泛型方法才比较好,不知道为何要这样设计.

Assert.StartsWith Assert.EndsWith

用于断言一个字符串是否以特定字符(串)开头(结尾),而且这两个方法都有一个重载用于指定是否忽略大小写

用过Nunit的同窗可能知道,Nunit里要实现区分大小写的StartsWith有点麻烦.

Assert.True Assert.False

用于断言两个布尔变量(包括可空)的值是不是真(假).

Assert.All

用于断言集合里的全部元素是否都知足经过测试,奇怪的是这个方法接收的是Action 委托而不是Func<T,bool>类型委托.这将致使写出来的代码看上去有点怪异.

下面举个用于断言集合里的元素值是否都大于0的例子来看看如何使用它

[Fact]
        public void Test1()
        {
            int[] intt =  {3, 4, 5, 9, 22};
            Assert.All(intt, t => Assert.True(t > 0));
        }

注意以上写法,因为不接收Func<T,bool>类型委托,所以以上方法不能想固然的写为 Assert.All(intt, t => t>0); 这样将致使编译错误.

Assert.Contains

这个方法有多个重载,功能也很是多,可是语义都很是明确.

用于断言字符串是否包含指定字符串

至关于字符串里的Contains,而且表现行为相似,也有一个重载支持不区分大小写

用于断言集合是否包含指定元素

请看如下代码

[Fact]
        public void Test1()
        {
            int[] intt = {3, 4, 5, 9};
            Assert.Contains(4, intt);
        }

以上代码用于断言集合intt里是否包含元素4,显然是包含的

注意,对于包含引用对象的集合判断是否包含某一元素这一个元素必须和集合中的某一个元素的引用地址同样.这不少时候并非咱们想要的行为,多数时候引用对象的对应的字段分别相等时咱们就认为它相等,更极端的状况是某些状况下两个对象只有某一个或者少数几个字段相等时咱们也认为相等,这要看具体实际业务.前面讲Nunit时对这个问题有过详细讲解.这里Contains方法一样有一个重载以支持一个比较器,用于自定义相等性逻辑.

还有一点须要指出,Contains方法只能断言集合是否包含某一个元素,而不能断言是否包含某几个元素(也即一个集合是不是另外一个集合的子集),Nunit里并无提供直接方法用于处理这样的问题.有些同窗可能认为Assert.Subset是用来解决这个问题的,然而并非,Subset只能用于实现了ISet接口的集合,不少时候并非特别有帮助.

用于断言集合中是否包含指定类型的元素

这个重载方法语义稍显不是很明确,它其实至关于linq里的any方法,只要有一个(一些)知足条件的元素就会返回true

[Fact]
        public void Test1()
        {
            int[] intt = {3, 4, 5, 9};
            Assert.Contains(intt, a => a > 3);
        }

以上方法用于断言intt集合中是否包含大于3的元素,显然是包含的.

Assert.Empty

用于断言集合是否不包含任何元素,也即集合是不是一个空集合

Assert.Matches

此方法接收两个参数,第一个表示要匹配的正则规则,第二个表示要测试的字符串,语义相似正则表达式里的IsMatch

Assert.InRange

用于断言指定元素是否在指定的范围内

[Fact]
        public void Test1()
        {
            Assert.InRange(20, 3, 20);
        }

以上代码片断断言20是否在3到20这个范围内,显然是在的.

此方法支持一个重载接收一个Icomparer参数用于自定义一个比较器,这样就能够判断任意对象是否在某一范围内,有这方面需求的同窗能够研究一下

Assert.Single

用于断言集合只包含 一个 元素,这个方法有几个重载.

重载1

用于断言集合中是仅包含一个元素,这个重载可能大部分时候不是颇有用

[Fact]
        public void Test1()
        {
            Assert.Single(new[] {3});
        }

重载2 接收一个参数,用于断言这个元素是不是指定元素

[Fact]
       public void Test1()
       {
           Assert.Single(new[] {3,4,5,9},3);
       }

以上代码断言集体中只有一个元素是3

此方法至关于对集合执行linq的first方法

重载3 接收一个predict类型委托,用于断言这个元素是否知足指定条件

[Fact]
       public void Test1()
       {
           Assert.Single(new[] {3,4,5,9},a=>a>5);
       }

以上方法断言集合中的这个是否只包含一个大于5的元素.

此方法至关于linq里面的single方法的有参重载

Assert.IsAssignableFrom

用于断言实例对象的类型是不是一个类型的子类(或者自己)

这个方法Nunit里也有,和反射里的IsAssignableFrom语义相同

Assert.IsType

用于断言实例对象的类型是不是某一指定类型

和IsAssignableFrom相比,此方法要求实例对象类型必须确切地是某一类型