.netcore持续集成测试篇之开篇简介及Xunit基本使用
为了支持跨平台,微软为.net平台提供了.net core test sdk,这样第三方测试框架诸如Nunit,Xunit等只需要按照sdk提供的api规范进行开发便可以被dotnet cli工具调用,这样就解决了在持续集成过程中第三方框架依赖于windows平台上的各自runner的问题,使得测试框架开发者不需要花费很大功夫就可以快速迁移到.net core平台,同时封装了各测试框架的实现细节,对外暴露统一调用接口,大大减少devops开发者的工作量.
作为单元测试基础知识介绍,这里只介绍常用单元测试框架Nunit和Xunit如何在.net core平台上使用,并介绍由于.net core的变化所引起的需要注意的测试代码的相应改变,对于如何在Jenkins环境中自动完成测试的相关内容Jenkins基础知识里面介绍
考虑到实际工作中可能有的项目组已经使用或者尝试使用xunit,并且.net core对xunit支持较好,诸多开源项目的单元测试也都使用的是Xunit,本章节作为补充对Xunit基础知识进行讲解,以帮助还不太了解这个框架的同学快速入门.
我们知道在.net framework下相要对mvc项目进行集成测试非常困难,一方面.net http管道里有很多黑盒子,开发者对它的实现细节一无所知,二者需要mock的对象太多,工作量巨大.因此很难在持续集成环境中对web项目进行集成测试.开发者或者测试人员大都依赖postman,fiddler,以及浏览器的http请求插件来进行集成测试,这样带来的一个很大问题这些http请求很难复用,更难以有效的组织管理.即使使用postman这样强大的http工具如果测试接口过多代码也会变得一塌糊涂,过一段时间后想要知道哪个方法是测试哪个接口用的就需要通过搜索来导航到指定的测试方法,并且很多时候有于各模块有相同名称的方法,往往需要先找到方法所在的area,然后再找到controller然后再找到相应方法...如果出现问题的代码过多往往把开发者搞的焦头烂额,苦不堪言.
幸运的是在.net core里很容易模拟一个httpt管道,这一方面使得集成测试在持续集成环境中使用提供了可能,另一方http请求写成程序里,可以很方便的导航到指定的测试方法,极大提供可维护性.本章节最后会介绍如何搭建一个.net core web项目的selfhost环境以供在单元测试框架中使用.
下面我们将简要介绍如何在vs中配置xunt环境以及Xunit断言的基本使用
.net core 中使用Xunit
Xunit是.net平台下的一款单元测试工具,类似Nunit.但是更为轻量,更加专注于单元测试而不像Nunit提供了很多额外的功能
.net core对Xunit支持较好,VisualStudio 2017提供有一个Xunit单元测试模板可以很方便的创建一个Xunit单元测试项目.
如图,在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相比,此方法要求实例对象类型必须确切地是某一类型
.netcore持续集成测试篇之开篇简介及Xunit基本使用的更多相关文章
- .netcore持续集成测试篇之搭建内存服务器进行集成测试一
系列目录 在web项目里,我们把每一层的代码的单元测试都通过并不代表程序能正常运行,因为这个过程缺失了http管道,很多时候我们还还需要把项目布在iis环境中或者在vs里启动iis express服务 ...
- .netcore持续集成测试篇之web项目验收测试
系列目录 通过前面的单元测试,我们能够保证项目的基本模块功能逻辑是正常的,通过集成测试能够保证接口的请求是正常的.然而最终项目交付我们还需要对项目进行页面的行为进行测试,比如页面布局是否正常,按钮是否 ...
- .netcore持续集成测试篇之Xunit结合netcore内存服务器发送post请求
系列目录 Web项目中,很多与用户数据交互的请求都是Post请求,想必大家都用过HttpClient构造过post请求,这里并不对HttpClient做详细介绍,只介绍一些常用的功能.并结合AutoF ...
- .netcore持续集成测试篇之测试方法改造
系列目录 通过前面两节讲解,我们的测试类中已经有两个测试方法了,总体上如下 public class mvc20 { private readonly HttpClient _client; publ ...
- .netcore持续集成测试篇之MVC测试
前面我们讲的很多单元测试的的方法和技巧不论是在.net core和.net framework里面都是通用的,但是mvc项目里有一种比较特殊的类是Controller,首先Controller类的返回 ...
- .netcore持续集成测试篇之 .net core 2.1项目集成测试
系列目录 从.net到.net core以后,微软非常努力,以每年一到两个大版本的频率在演进.net core,去年相继发布了.net core 2.1和2.2,其中2.1是长期支持版,不断的快速更新 ...
- .netcore持续集成测试篇之Xunit数据驱动测试一
系列目录 Nunit里提供了丰富的数据测试功能,虽然Xunit里提供的比较少,但是也能满足很多场景下使用了,如果数据场景非常复杂,Nunit和Xunit都是无法胜任的,有不少测试者选择自己编写一个数据 ...
- .net持续集成测试篇之Nunit常见断言
系列目录 Nunit测试基础之简单断言 在开始本篇之前需要补充一些内容,通过前面搭建Nunit测试环境我们知道要使一个方法成为单元测试方法首先要在此方法所在类加上TestFixture注解,并且在该方 ...
- .net持续集成测试篇之Nunit文件断言、字符串断言及集合断言
使用前面讲过的方法基本上能够完成工作中的大部分任务了,然而有些功能实现起来还是比较麻烦的,比如说字符串相等性比较不区分大小写,字符串是否匹配某一正则规则,集合中的每一个(某一个)元素是否符合特定规则等 ...
随机推荐
- throw 与 throws的比较
说实话,今天在公司的实习,确确实实编号被严重打脸了,说真的,自己的基础功不扎实,希望慢慢弥补吧! 抛出异常有三种形式,一是throw,一个throws,还有一种系统自动抛异常,下面它们之间的异同. 一 ...
- C++ hdu 例题:不要62 题解
例题:不要62 同步数位DP 需要统计区间[l,r]的满足题意的数的个数,这往往可以转换成求[0,r]-[0,l) 基本思想与方法 有了上述性质,我们就可以从高到低枚举第一次<n对应位是哪一位. ...
- python学习 -女神或者男神把微信消息撤回后好慌,有了这个妈妈再也不担心你看不到女神或者男神撤回的消息了(超详解)
简介 有时候在忙工作,女朋友发了一个消息,就撤回了,但是人天生的都有一颗好奇心,而且在当今这个时代找个女朋友不容易,一个程序猿找一个女朋友更是不容易的.人家好不容易跟你,你还不得把人家当老佛爷侍候着, ...
- 2018.12.1 万圣节的小L
我回来啦 试题描述 今天是万圣节,小L同学开始了一年一度的讨要糖果游戏,但是在刚刚过去的比赛中小有成就的他打算给自己增加一点难度:如果没有讨到每一家的糖果就算输. 已知小L共有n(n不大于10000) ...
- Python之Pandas库学习(一):简介
官方文档 1. 安装Pandas windos下cmd:pip install pandas 导入pandas包:import pandas as pd 2. Series对象 带索引的一维数组 创建 ...
- JQuery学习笔记(3)——节点操作 节点查找
插入节点 内部插入 所谓的内部插入,就是指在节点里面的插入,而外部插入,则是在节点外面插入. append() prepend() appendTo() prependTo() append和prep ...
- go 学习笔记之初识 go 语言
Go 是一种开源编程语言,可以轻松构建简单,可靠,高效的软件. 摘录自 github: https://github.com/golang/go,其中官网(国外): https://golang.or ...
- 【Android UI】顶部or底部菜单的循环滑动效果一
实现了分页的滑动效果,做的demo流畅运行 注:貌似支持的样式(控件)有一定的限制,我试过短信的listview页面,暂无法实现滑动效果 java文件:MainActivity.java.Activi ...
- Git命令行之快速入门
从头开始创建一个版本库,添加一些内容,然后管理一些修订版本. 有两种建立 Git版本库 的基础技术.第一:从头开始创建,用现有的内容填充它.第二:可以克隆一个已有的版本库.这里选择从一个空的版本库开始 ...
- Python3安装与使用urllib2包之小坑
Python3 安装urllib2包之小坑 Python3.6.6或者说python3.x找不到urllib2语法问题修改之后,会报一个没有安装urllib2的包的错误. 通过pip install ...