好代码是管出来的——.Net Core中的单元测试与代码覆盖率

 测试对于软件来说,是保证其质量的一个重要过程,而测试又分为很多种,单元测试、集成测试、系统测试、压力测试等等,不同的测试的测试粒度和测试目标也不同,如单元测试关注每一行代码,集成测试关注的是多个模块是否能正常的协同工作。
  当我们在衡量代码好坏时,其中一点就是这些代码是否进行了单元测试,测试的质量、代码覆盖率怎么样?本文将从以下几个方面介绍.Net Core中的单元测试:

  • 单元测试简介

  • .Net Core中的单元测试框架

  • 使用xUnit.Net对.Net Core应用进行单元测试

    • 创建xUnit.Net测试项目

    • 编写测试方法

    • 断言

    • 运行单元测试

  • Mock

  • 单元测试代码覆盖率

  • 小结

单元测试简介

  单元测试是指对软件中的最小可测试单元进行检查验证,而.Net中最小可测试单元就是类和方法,单元测试是白盒测试关注于代码执行逻辑,所以单元测试代码一般也由开发人员编写。
  单元测试关注的两个重点就是最小可测试单元和代码逻辑,但是很多情况下,一个类或者是方法它会依赖一些外部组件,如其他开发人员写的代码、第三方类库、数据库、网络等,当被测试的代码与这些组件紧耦合时,那么这段代码将可能是不可测的,如一个方法中依赖一个数据库组件去访问数据库,那么在执行这个方法时,必然要与数据库交互,如果没有数据库,那么该方法就无法运行。
  所以单元测试不仅是对代码逻辑进行检查,同时还对整个代码结构有所限制,面向对象编程时应当遵循“依赖倒置”原则,模块应该依赖抽象,抽象不应该依赖实现。并且所依赖的抽象,应该显示的通过构造或者方法参数进行暴露,让组件的使用者对组件的依赖一目了然。
  而在单元测试时为了屏蔽这些抽象依赖,不同测试框架中提供了stub、mock、fake等方式对抽象进行模拟,以便于代码能够正常执行。

.Net Core中的单元测试框架

  .Net Core中常用的单元测试的框架有MSTest、NUnit和xUnit.net,它们的使用方法都非常相似,都是通过特性标记的方式声明测试方法,然后在方法中使用断言(Assertions)来判别方法执行结果是否达到预期。
  这三个框架中MSTest是与VS集成的,而NUnit和xUnit.net都加入了.Net基金会,下面两个图分别是三个框架特性和断言的比较(内容来自:https://xunit.github.io/docs/comparisons):
  特性:

  640?wx_fmt=png

  断言(部分):

  640?wx_fmt=png 

  三个框架自有优点,但xUnit.net使用更广泛一些(许多开源项目都使用xUnit.net,包括ASP.NET Core MVC、EF Core等项目),支持.Net下的大部分平台(.Net Fx、.Net Core、UWP、Xamarin),并且具有非常好的可拓展性。

使用xUnit.Net对.Net Core应用进行单元测试

  本文使用xUnit.Net框架来对.Net Core程序进行单元测。

创建xUnit.Net测试项目

  在解决方案中添加.Net Core的被测试项目以及xUnit测试项目:

  640?wx_fmt=png

  目录结构:

  640?wx_fmt=png

  xUnit测试项目还提供了相应的代码分析器来帮助编写测试代码:

  640?wx_fmt=png

编写测试方法

  在被测试的项目中添加一个计算器类型,并添加加法运算的方法:

   640?wx_fmt=png

  在测试项目中添加Calulator方法的测试代码:

  640?wx_fmt=png

断言

  在程序中,断言指的是一个表达式语句执行时总是为真(True),它有助于代码阅读、调试、编译和缺陷检测,当断言内表达式执行为True时,不会执行任何操作,当结果为false时将会输出一些异常信息,下图是.Net中System.Diagnositics命名空间下提供的代码调试使用的断言用法(在调试程序时,当参数x < y就会中断并抛出异常信息):

  640?wx_fmt=png

  更多参考:https://docs.microsoft.com/en-us/visualstudio/debugger/assertions-in-managed-code
  在单元测试中,测试方法也是使用断言的方式来判别程序执行结果与预期结果是否相符:

  640?wx_fmt=png

  xUnit.net中的断言参考:https://github.com/xunit/assert.xunit

运行单元测试

  在VS中可以使用VS的测试窗口运行测试方法:

  640?wx_fmt=jpeg

  运行结果(测试通过):

  640?wx_fmt=png

  运行结果(测试未通过):

  640?wx_fmt=png

Mock

  在文章前面提到过,面向对象编程应该显示的依赖抽象,单元测试时应该将屏蔽依赖的影响(无论是依赖还未实现,或者实现的依赖会阻碍代码执行),为了满足这一需求出现了Mock、Fake等方式,其原理就是创建一个"假"的"空"的依赖,并用其替代真实依赖,以确保代码能够运行。
  .Net中一个常用的Mock框架是Moq,本文将使用Moq来介绍如何对依赖进行模拟:
  1. 编写需要依赖的代码:

  640?wx_fmt=png

  640?wx_fmt=png

  上面代码中UserManager依赖一个用户的仓储类型,该仓储将会与数据库交互。
  2. 为测试项目安装Moq组件:

  640?wx_fmt=jpeg

  3. 编写测试代码:

  640?wx_fmt=png

  上面代码通过Moq组件Mock了一个IUserRepository的类型,并将其Add方法设置并返回true(注:设置方法时参数的数据要与调用时使用的一致),最后通过Mock的对象实例Object来创建UserManager实例。
  最后断言当创建用户时,年龄为负数则抛出FormatException。
  4. 运行测试:

  640?wx_fmt=png

  测试成功。

单元测试代码覆盖率

  测试代码覆盖率是对单元测试的一种度量,可以用来衡量单元测试是否达标,一般将代码测试目标定到80%-90%之间,为了保证代码覆盖率,在写测试用例时就要从语句覆盖、条件覆盖、路径覆盖等方面进行充分考虑。
  而.Net Core中如何在测试时计算代码覆盖率呢?如果使用VS的企业版,那么VS自带了代码覆盖率分析工具:

  640?wx_fmt=png 

  详情参考:https://docs.microsoft.com/en-us/visualstudio/test/using-code-coverage-to-determine-how-much-code-is-being-tested
       https://github.com/Microsoft/vstest-docs/blob/master/docs/analyze.md#coverage
  注:VS集成了MSTest,所以代码覆盖分析工具对MSTest支持非常好,但对xUnit.Net的支持如何笔者未进行测试。

  对于xUnit.net来说,要分析测试代码覆盖率还可以通过“OpenCover”和“ReportGenerator”工具完成,下面就介绍如何通过这两个工具完成代码覆盖率的分析:
  1. 下载并安装OpenCover,在OpenCover的GitHub上下载最新release的zip包,并解压缩到指定目录下,并将OpenCover目录添加到环境变量中:

  640?wx_fmt=png

  地址:https://github.com/OpenCover/opencover/releases

  2. 通过命令行使用OpenCover来完成覆盖率分析:
  OpenCover有许多参数,具体参考:https://github.com/OpenCover/opencover/wiki/Usage
  在本例中,仅需要指定目标程序是dotnet.exe,目标程序参数是test(注:.Net Core的测试功能实际上是用.Net Core的CLI命令 dotnet test完成的),另外指定输出文件名,register参数用于注册代码分析器默认使用user即可,-filter参数用于过滤不需要分析覆盖率的程序集和类型,-oldstyle是为了支持.Net Core程序添加的参数(详见:https://github.com/OpenCover/opencover/issues/595)
  另外为了能够满足测试需要在相关项目文件中添加以下节点(详见:https://github.com/Microsoft/vstest/issues/800):

<PropertyGroup><DebugType>full</DebugType></PropertyGroup>

  最后在项目目录下执行以下命令:
  OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test" -output:coverage.xml -register:user -filter:"+[*]* -[*Moq]* -[xunit*]*" -oldstyle

  640?wx_fmt=png

  生成的结果: 

  4. 通过ReportGenerator生成可读报表:
  下载地址:https://github.com/danielpalme/ReportGenerator/releases
  注:下载解压后将ReprotGenerator的目录添加到环境变量,以便使用。
  执行以下命令:
  ReportGenerator.exe "-reports:coverage.xml" "-targetdir:report"

  640?wx_fmt=png

  生成内容:

  640?wx_fmt=png

  打开index.htm文件:

  640?wx_fmt=png

  5. 在项目中创建一个bat文件,用于保存代码覆盖率检测和报表生成命令,便于使用:

  640?wx_fmt=png

小结

  本文主要介绍了如何使用xUnit.net测试框架完成.Net Core程序的单元测试,以及通过Moq框架来模拟测试目标的相关依赖,避免了其它组件对测试代码的影响。
  文章的最后介绍了如何使用开源工具OpenCover和ReportGenerator工具来实现.Net Core单元测试代码覆盖率分析,这种方案相对VS企业版自带的工具使用上要麻烦一些,但好在工具都是开源的,对持续集成也有比较好的支持,所以不失为一种好的解决方案。
  单元测试仅能保证软件的最小可执行单元是正确的,真正的软件是由这些最小可执行单元组成的一个整体,单元的正确性无法保证整体的正确性,下篇文章将对.Net Core的集成测试进行介绍。

本文链接:https://www.cnblogs.com/selimsong/p/9263957.html 

测试代码:https://github.com/yqszt/xUnitTestDemo

参考:
  https://en.wikipedia.org/wiki/Unit_testing
  https://docs.microsoft.com/en-us/dotnet/core/testing/
  https://github.com/aspnet/Home/wiki/Engineering-guidelines#unit-tests-and-functional-tests
  http://asp.net-hacker.rocks/2017/03/31/unit-testing-with-dotnetcore.html
  https://stackoverflow.com/questions/261139/nunit-vs-mbunit-vs-mstest-vs-xunit-net
  http://blog.ploeh.dk/2010/04/26/WhyImmigratingfromMSTesttoxUnit.net/
  https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test?tabs=netcore21
  https://stackoverflow.com/questions/38425936/how-to-measure-code-coverage-in-asp-net-core-projects-in-visual-studio
  http://dotnetliberty.com/index.php/2016/02/22/moq-on-net-core/
  https://github.com/moq/moq4
  https://stackoverflow.com/questions/41384459/opencover-reports-missing-pdbs-when-pdbs-are-present-xunit-net-core
  https://github.com/OpenCover/opencover
  https://github.com/danielpalme/ReportGenerator

相关文章:

原文地址https://www.cnblogs.com/selimsong/p/9263957.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/320916.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P3694-邦邦的大合唱站队【状压dp】

正题 题目链接:https://www.luogu.com.cn/problem/P3694 题目大意 nnn个人&#xff0c;有mmm个队伍&#xff0c;每个人都属于一个队伍。要求叫出一些人来&#xff0c;然后任意插入出来的空隙中使得同一队的人在一起。求最少出列人数。 解题思路 如果知道最终的队列就可以十分…

数字图像处理作业

图像处理作业 1 取sT(r)11(mr)EsT(r)\frac{1}{1(\frac{m}{r})^E}sT(r)1(rm​)E1​ 其中rrr为原始亮度&#xff0c;mmm为输入区间的中点&#xff0c;EEE描述曲线的陡峭程度 2 一幅8灰度级图像具有如下所示的直方图&#xff0c;求直方图均衡后的灰度级和对应概率&#xff0c;…

【差分】侦察兵

侦察兵 题目大意&#xff1a; 给出一个图&#xff0c;再给一些点&#xff0c;求出这些点左上角和右下角的数之和 原题&#xff1a; 题目描述 mxy 沉迷于一个辣鸡游戏不可自拔。 游戏地图是一个 n*n 的矩形&#xff0c;在每个单位格子上有一个数字&#xff0c;代表当前位置…

深港澳大湾区(深圳).NET技术交流会圆满成功

2018年7月7日一场以.NET Core微服务和机器学习为主题的交流会成功在深圳职业技术学院落下帷幕。这次活动在短短的一周时间内&#xff0c;报名人数超过了170人&#xff0c;除了一些同学临时有事&#xff0c;基本都到现场了&#xff0c;特别感谢深职院的软创工作室对这次活动的支…

P5322-[BJOI2019]排兵布阵【背包】

正题 题目链接:https://www.luogu.com.cnp/problem/P1768 题目大意 nnn个城池&#xff0c;有sss个玩家对于每个城池有一定的兵。对于所有玩家的每个城池都有派兵一个人数&#xff0c;要求派兵人数之和为mmm。如果你的派兵数列每大于一个玩家派兵数量的两倍那么就可以获得该城池…

图像处理作业二

作业信息 1、证明3.44和3.45的正确性 g(x,y)1K∑i1Kgi(x,y)g(x,y)\frac{1}{K}\sum_{i1}^K g_i(x,y)g(x,y)K1​∑i1K​gi​(x,y) E[g(x,y)]f(x,y)E[n(x,y)]f(x,y)E[g(x,y)]f(x,y)E[n(x,y)]f(x,y)E[g(x,y)]f(x,y)E[n(x,y)]f(x,y) D[g]E[(g−E[g])2]E[g2]−E[g]2E[f22f(n1n2...nK…

【模拟】遭遇战

遭遇战 题目大意&#xff1a; 在一个nn的范围内两个人在跑&#xff08;san&#xff09;步&#xff0c;问他们在哪里相遇 原题 题目描述 mxy 沉迷于一个辣鸡游戏不可自拔。 游戏地图是一个 n*n 的矩形&#xff0c;左上角为&#xff08;0,0&#xff09;&#xff0c;右下角为…

.Net Core开发日志——Peachpie

.Net Core的生态圈随着开源社区的力量不断注入至其中&#xff0c;正在变得越来越强盛&#xff0c;并且不时得就出现些有意思的项目&#xff0c;比如Peachpie&#xff0c;它使得PHP的代码迁移到.Net Core项目变得可能。从创建简单的入门程序开始可以更容易地体会其特性。首先安装…

P5268-[SNOI2017]一个简单的询问【莫队】

正题 题目链接:https://www.luogu.com.cn/problem/P5268 题目大意 nnn个数的一个序列&#xff0c;定义get(l1,r1,x)get(l_1,r_1,x)get(l1​,r1​,x)表示区间[l1,r1][l_1,r_1][l1​,r1​]中有多少个xxx。 每次询问(l1,r1,l2,r2)(l_1,r_1,l_2,r_2)(l1​,r1​,l2​,r2​)求∑x∞…

图像处理作业第三次

图像处理作业第三次 1.根据书中对傅立叶变换的定义&#xff0c;证明课本165页上有关傅立叶变换的平移性质。 F(u−u0,v−v0)F(u-u_0,v-v_0)F(u−u0​,v−v0​) ∑x0M−1∑y0N−1f(x,y)e−j2π((u−u0)x/M(v−v0)y/N)\sum_{x0}^{M-1}\sum_{y0}^{N-1}f(x,y)e^{-j2\pi((u-u_0)x/M…

初一模拟赛(4.20)

成绩&#xff1a; rankrankranknamenamenamescorescorescoreT1T1T1T2T2T2T3T3T3T4T4T4111lyflyflyf400400400100100100100100100100100100100100100222wjjwjjwjj310310310100100100100100100100100100101010333hkyhkyhky300300300100100100100100100100100100000333cyzcyzcyz30…

.NET Core开发日志——Middleware

熟悉ASP.NET架构的开发者一定对于HTTP Modules与HTTP Handlers不陌生。两者的作用主要是对网络请求执行特定的处理工作。而在.NET Core中&#xff0c;它们都被Middleware(中件间)取代了。之前的Http Modules和HTTP Handlers是如下图般处理请求的&#xff1a;现在变成了这样&…

P3850-[TJOI2007]书架【Splay】

正题 题目链接:https://www.luogu.com.cn/problem/P3850 题目大意 一个书架上有nnn本书&#xff0c;进行mmm次插入操作&#xff0c;然后qqq次询问一个位置上的书。 解题思路 用SplaySplaySplay进行插入操作&#xff0c;然后直接查询即可 codecodecode #include<cstdio&g…

【并查集】家族 (ssl 1896)

家族 ssl 1896 题目大意&#xff1a; 合并一些集合&#xff0c;然后判断某两个点是否在同一个集合内 原题&#xff1a; 题目描述 若某个家族人员过于庞大&#xff0c;要判断两个是否是亲戚&#xff0c;确实还很不容易&#xff0c;现在给出某个亲戚关系图&#xff0c;求任…

模式识别作业

模式识别作业 1.说明判别分类器(如logistic回归)与上述特定类别的高斯朴素贝叶斯分类器之间的关系正是logistic回归所采用的形式。 经过第2问更加普遍的推导过程&#xff1a; 对应参数为&#xff1a; 二次项&#xff1a; v[σ112−σ1022σ112σ102,...,σD12−σD022σD12…

Identity Server 4 - Hybrid Flow - Claims

前一篇 Identity Server 4 - Hybrid Flow - MVC客户端身份验证: https://www.cnblogs.com/cgzl/p/9253667.htmlClaims我不知道怎么样翻译这个词比较好, 所以我一般就不翻译了.在前一篇文章里, MVC客户端配置身份认证的时候有这么一句话(Startup的ConfigureServices):JwtSecurit…

图像处理作业第7次

图像处理作业第7次 1.请根据课本中Z变换的定义&#xff0c;证明如下结论。 (1)若x(n)x(n)x(n)的ZZZ变换为X(z)X(z)X(z)&#xff0c;则(−1)nx(n)(-1)^nx(n)(−1)nx(n)的ZZZ变换为X(−z)X(-z)X(−z) 根据ZZZ变换的定义 X(z)∑x(n)z−n,∑(−1)nx(n)z−n∑x(n)(−z)−nX(−z)X(z…

【prim】【最小生成树】最优布线问题(ssl 1612)

最优布线问题 ssl 1612 题目大意&#xff1a; 求最小生成树 原题&#xff1a; 题目描述 学校有n台计算机&#xff0c;为了方便数据传输&#xff0c;现要将它们用数据线连接起来。两台计算机被连接是指它们之间有数据线连接。由于计算机所处的位置不同&#xff0c;因此不同…

P5304-[GXOI/GZOI2019]旅行者【最短路】

正题 题目链接:https://www.luogu.com.cn/problem/P5304 题目大意 nnn个点mmm条边的一张有向图&#xff0c;有kkk个关键点&#xff0c;求距离最短的一对关键点。 解题思路 我们能够O(nlog⁡n)O(n\log n)O(nlogn)的进行一个起点或多个起点同时的最短路&#xff0c;但是这题显然…

微软宣布ASP.NET Core 2.0正式支持OData标准

近日&#xff0c;OData 团队在微软开发者博客上宣布&#xff0c;ASP.NET Core 2.0 已正式支持 OData 标准&#xff0c;开发者现在可通过包管理器 NuGet 来获取 Microsoft.AspNetCore.OData 包。此软件包包含在使用 ASP.NET Core MVC 时创建 OData v4.0 端点以及支持 Web API 的…