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

单元测试简介

  单元测试是指对软件中的最小可测试单元进行检查验证,而.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):
  特性:

  

  断言(部分):

   

  三个框架自有优点,但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测试项目:

  

  目录结构:

  

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

  

编写测试方法

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

  

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

  

断言

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

  

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

  

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

运行单元测试

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

  

  运行结果(测试通过):

  

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

  

Mock

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

  

  

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

  

  3. 编写测试代码:

  

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

  

  测试成功。

单元测试代码覆盖率

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

   

  详情参考: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目录添加到环境变量中:

  

  地址: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):

  1. <PropertyGroup>
  2. <DebugType>full</DebugType>
  3. </PropertyGroup>

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

  

  生成的结果: 

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

  

  生成内容:

  

  打开index.htm文件:

  

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

  

小结

  本文主要介绍了如何使用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

好代码是管出来的——浅谈.Net Core的代码管理方法与落地(更新中...)

好代码是管出来的——.Net Core中的单元测试与代码覆盖率的更多相关文章

  1. .NET Core: 在.NET Core中进行单元测试

    单元测试能够帮助开发人员确保所开发的模块.类以及类中的方法等的正确性,在项目开发过程中,及时进行单元测试能够避免不必要的BUG以及提高测试效率. 在本文中,我们会分别来学习如何使用MSTest.xUn ...

  2. 在ASP.NET Core中使用Apworks开发数据服务:对HAL的支持

    HAL,全称为Hypertext Application Language,它是一种简单的数据格式,它能以一种简单.统一的形式,在API中引入超链接特性,使得API的可发现性(discoverable ...

  3. NET Core中使用Apworks

    NET Core中使用Apworks HAL,全称为Hypertext Application Language,它是一种简单的数据格式,它能以一种简单.统一的形式,在API中引入超链接特性,使得AP ...

  4. 好代码是管出来的——.Net Core集成测试与数据驱动测试

    软件的单元测试关注是的软件最小可执行单元是否能够正常执行,但是软件是由一个个最小执行单元组成的集合体,单元与单元之间存在着种种依赖或联系,所以在软件开发时仅仅确保最小单元的正确往往是不够的,为了保证软 ...

  5. 使用依赖关系注入在 ASP.NET Core 中编写干净代码

    ASP.NET Core 1.0 是 ASP.NET 的完全重新编写,这个新框架的主要目标之一就是更多的模块化设计.即,应用应该能够仅利用其所需的框架部分,方法是框架在它们请求时提供依赖关系.此外,使 ...

  6. [转]使用依赖关系注入在 ASP.NET Core 中编写干净代码

    本文转自:http://blog.jobbole.com/101270/ 原文出处: Steve Smith    ASP.NET Core 1.0 是 ASP.NET 的完全重新编写,这个新框架的主 ...

  7. 在Asp.Net Core中配置使用MarkDown富文本编辑器实现图片上传和截图上传(开源代码.net core3.0)

    我们的富文本编辑器不能没有图片上传尤其是截图上传,下面我来教大家怎么实现MarkDown富文本编辑器截图上传和图片上传. 1.配置编辑器到html页 <div id="test-edi ...

  8. 在Asp.Net或.Net Core中配置使用MarkDown富文本编辑器有开源模板代码(代码是.net core3.0版本)

    研究如何使用Markdown你们可能要花好几天才能搞定,但是看我的文章或者下载了源码,你搞定一般在10分钟之内.我先给各位介绍下它: Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯 ...

  9. 一行代码在 .NET Core 中快速使用 log4net

    原文:一行代码在 .NET Core 中快速使用 log4net 1. .NET Core 控制台程序中使用 第一步:添加引用 Install-Package log4net 第二步:将附件 LogH ...

随机推荐

  1. Android studio简单布局之view基本属性

    本人属于自学上路,目前是在入门阶段,所以有些内容实质性比较少,请各位大佬多多包涵. 视图view的基本属性: layout_margin:定义视图与周围视图之间的空白距离 layout_padding ...

  2. MySQL性能优化总结___本文乃《MySQL性能调优与架构设计》读书笔记!

    一.MySQL的主要适用场景 1.Web网站系统 2.日志记录系统 3.数据仓库系统 4.嵌入式系统 二.MySQL架构图: 三.MySQL存储引擎概述 1)MyISAM存储引擎 MyISAM存储引擎 ...

  3. 视频直播 object 标签属性详解

    最近在做视频直播这一块的,html5的video不能实现此功能,在网上查找了资料,觉得很有用. 一.介绍: 我们要在网页中正常显示flash内容,那么页面中必须要有指定flash路径的标签.也就是OB ...

  4. JVM监控命令

    1.概述Jcmd是一个诊断Jvm的命令集工具, 集成了包括Jps, Jstack以及采集JFR信息等功能. 它必须运行在被诊断Jvm进程的同一台机器上.1)查询JVM进程及PID/dapeng-con ...

  5. Kafka 消费者相关配置

    消费者相关配置类为  org.apache.kafka.clients.consumer.ConsumerConfig 具有以下配置参数 1. GROUP_ID_CONFIG = "grou ...

  6. String、StringBuffer和StringBuilder类的区别

    Java提供了String.StringBuffer和StringBuilder类来封装字符串,并提供了一系列操作字符串对象的方法. 它们的相同点是都用来封装字符串:都实现了CharSequence接 ...

  7. 多线程工具类:CountDownLatch、CyclicBarrier、Semaphore、LockSupport

    ◆CountDownLatch◆ 假如有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以.比如你想要买套房子,但是呢你现在手上没有钱.你得等这个月工资发了.然后年终奖发了.然后朋友借你得钱 ...

  8. 前端性能优化之gzip

    前言: 如果你是个前端开发人员,你肯定知道线上环境要把js,css,图片等压缩,尽量减少文件的大小,提升响应速度,特别是对移动端,这个非常重要.常用的前端性能优化方法有如下几种 一.减少http请求 ...

  9. 编辑器开发之 Selection 对象的学习

    上一篇,介绍了 range 对象的一些属性和方法,了解了一些基本操作,现在来介绍另外一个重要的对象:selection 对象: MDN 的解释是:Selection 对象表示用户选择的文本范围或插入符 ...

  10. Python基础(生成器)

    二.生成器(可以看做是一种数据类型) 描述: 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我 ...