.Net Core单元测试规范

一、 前言

为了有效提升代码质量,保证DevOps的顺利进行。将全面开始采用单元测试进行覆盖,届时单元测试将完全纳入

到完整的持续构建生命周期中做为第一道质量把控的门槛。

二、 预期目标

1. 避免直接异常

考虑到单元测试的细化程度,在代码级别上出现的故障将能够通过单元测试进行快速的挖掘。特别对于部分通

用业务代码,在修改一处后其他关联地方一旦没有及时修改将会导致重大事故,而借助于单元可以完全避免这

类情况的发生。

2. 故障产生前置

由于单元测试不依赖外部其他环境,是完全属于代码级别的测试。所以开发者仅仅通过本地也可以进行测

试,保证在相关功能代码编写完成后立即进行相关测试保证代码在提交前就能够挖掘其中的问题。

3. 质量管控可视化

借助于持续构建,过程中所有的单元测试报告通过采集后将可以有效的反应整个项目中各个开发人员的质

量情况,并通过看板及时有效的反应。

三、 应用层单元测试

1. 相关技术

为了能够快速的进行单元测试,需要相关人员具备一定的技术基础,下面将会给出在当前情况下需要使

用的相关单元测试技术以便于开发人员进行基础的学习同时也能够基于官方文档进行更深入的学习以提

升对于对于复杂情况下的应对能力。

  • Moq

    考虑到当前架构的复杂性,其中大量采用了IOC技术,为了能够实现单元测试需要借助于相关的Mock技

    术对底层或者第三方服务接口的模拟以实现各类环境的验证作用。

  • xUnit

    核心单元测试框架,其提供了简单的操作方式。同时也能够支持dotnet指令直接进行相关测试的论证。

2. 仓储模拟

应用层服务都需要依赖外部的各类存储,为了避免对于外部环境的依赖。对于单元测试来说需要将需

要测试的应用服务依赖的仓储接口进行模拟,以便进行具体的测试工作,这里以如下的仓储接口为例:

/// <summary>
/// 产品仓储接口
/// </summary>
public interface IProductInfoRepositories : IRepository<ProductInfo, string>, ITransientDependency
{
/// <summary>
/// 查询产品详情
/// </summary>
/// <param name="id">主键</param>
/// <returns></returns>
Task<ProductInfo> GetProductInfoAsync(string id); /// <summary>
/// 查询产品列表
/// </summary>
/// <returns></returns>
Task<List<ProductInfo>> GetProductInfoListAsync(); /// <summary>
/// 修改产品包年折扣
/// </summary>
/// <param name="id">主键</param>
/// <param name="discount">折扣</param>
/// <returns></returns>
Task UpdateProductInfoDiscountAsync(string id, decimal discount); /// <summary>
/// 根据序号查询产品信息
/// </summary>
/// <param name="number">产品序号</param>
/// <returns></returns>
Task<ProductInfo> GetProductInfoByNumberAsync(string number);
}

确定我们需要进行模拟的仓储接口后,我们需要在对应的测试工程项目下新建Mocks文件

夹并在其中新建文件ProductInfoRepositoryMock类,其中我们需要使用moq进行仓储

接口的模拟,比如对其中的GetProductInfoAsync接口进行模拟:

mock.Setup(x => x.GetProductInfoAsync("01")).Returns(Task.FromResult(new ProductInfo
{
Id = "01",
Number = "2019061800001",
Name = "TMS全流程物流运输管理系统",
ImgUrl = "https://avatars2.githubusercontent.com/u/16951448?s=200&v=4",
Discount = 1
})); mock.Setup(x => x.GetProductInfoAsync("05")).Returns(Task.FromResult(new ProductInfo
{
Id = "05",
Number = "201906180005",
Name = "PMS供应商自主系统",
ImgUrl = "https://avatars2.githubusercontent.com/u/16951448?s=200&v=4",
Discount = (decimal)0.75
})); mock.Setup(x => x.GetProductInfoAsync("error")).Returns(Task.FromResult<ProductInfo>(null));

利用Setup方法选择需要进行模拟的接口x => x.GetProductInfoAsync("01"),而其中可以选定特定的参数也可

以通过It.IsAny()方法传入参数,表示任意参数调用该方法均返回相同返回值,否则可以根据入参的不

同从而决定不同的出参。对于出参则通过Returns方法中直接放置需要返回的数据。

3. 应用接口测试

完成以上仓储接口的模拟后,对于ProductInfoService来说需要依赖的外部环境都具备了,这时就可以将该对

象进行实例化:

var productInfoRepositoryMock = new ProductInfoRepositoryMock();
_productInfoService = new ProductInfoService(productInfoRepositoryMock.Create())

完成对象的创建后就可以开始编写具体的单元测试代码了,比如针对上述仓储对接口GetProductInfoAsync进

行了模拟,对应的我们则只能针对应用层接口中的GetProductInfoAsync进行测试,首先进行基本的常规测试:

[Theory]
[InlineData("01")]
[InlineData("05")]
public async Task GetProductInfoAsync_IsNormal(string id)
{
var item = await _productInfoService.GetProductInfoAsync(id); Assert.NotNull(item);
Assert.Equal(id, item.Id);
Assert.NotEmpty(item.Name);
Assert.NotEmpty(item.Number);
Assert.NotEmpty(item.ImgUrl);
}

从上述代码中可以看到其中存在Theory、InlineData这几个注解属性的使用,这类注解属性用于提供不同参

数情况下的单元测试的论证。单元测试往往不是仅考虑正常业务情况下对代码逻辑的测试,更多的还是对于异

常情况下业务代码的正常工作,所以以下还需要对于不存在该数据的情况进行测试。

[Fact]
public async Task GetProductInfoAsync_IsNull()
{
var error = await _productInfoService.GetProductInfoAsync("error"); Assert.Null(error);
}

4. 持续构建

当前我们的整体流水线采用Drone进行管理,所以需要针对.drone.yml增加相关流程节点以支持单元测试

的运行,具体需要增加的配置如下:

- name: UnitTest
image: harbor.vip56.cn/common/sonar:2.2
commands:
- cd test/LogisticsWebsiteUnitTest
- dotnet test --logger:"trx;LogFileName=unitTestLog.txt"
when:
event:
- pull_request
- push
brancch:
- dev

5. 报告反馈

通过上述持续构建中logger参数可以得知具体的单元测试结果将输出到当前目录下的TestResults

文件夹下,其中大致内容如下:

<UnitTest name="LogisticsWebsiteUnitTest.ProductInfoServiceUnitTest.GetProductInfoAsync_IsNormal(id: &quot;01&quot;)" storage="g:\gitlab\logisticswebsiteback\test\logisticswebsiteunittest\bin\debug\netcoreapp2.0\logisticswebsiteunittest.dll" id="e950b619-318c-720a-d6ae-08d1f3ab96ec">
<Execution id="61675f18-f972-4f59-901f-68b9f75680de" />
<TestMethod codeBase="G:\gitlab\logisticswebsiteback\test\LogisticswebsiteUnitTest\bin\Debug\netcoreapp2.0\LogisticsWebsiteUnitTest.dll" adapterTypeName="executor://xunit/VsTestRunner2/netcoreapp" className="LogisticsWebsiteUnitTest.ProductInfoServiceUnitTest" name="LogisticsWebsiteUnitTest.ProductInfoServiceUnitTest.GetProductInfoAsync_IsNormal(id: &quot;01&quot;)" />
</UnitTest>

四、 表现层单元测试

敬请等待

.Net Core单元测试规范的更多相关文章

  1. .NET Core 单元测试 MSTest

    .NET Core 单元测试 MSTest ,MSTest Framework 已经支持 .NET Core RC2 / ASP.NET Core RC2. 之前都是使用 xUnit.net ,现在 ...

  2. 单元测试系列:JUnit单元测试规范

    更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 原文链接:http://www.cnblogs.com/zishi/p/6762032.html Junit测试代 ...

  3. .Net Core 编码规范

    .Net Core 编码规范 标签: 未分类 概述 规范制定原则 方便代码的交流和维护. 不影响编码的效率,不与大众习惯冲突. 使代码更美观.阅读更方便. 使代码的逻辑更清晰.更易于理解. 术语定义 ...

  4. 单元测试系列之三:JUnit单元测试规范

    更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 原文链接:http://www.cnblogs.com/zishi/p/6762032.html Junit测试代 ...

  5. dotnet core 编程规范

    本文实际只是翻译 .NET Core foundational libraries 官方文档的编码风格 在 .NET Core foundational libraries项目使用的编程规范默认就是 ...

  6. .Net基础——程序集与CIL HttpClient封装方法 .Net Core 编码规范 C#中invoke和beginInvoke的使用 WebServeice 动态代理类

    .Net基础——程序集与CIL   1. 程序集和CIL: 程序集是由.NET语言的编译器接受源代码文件产生的输出文件,通常分为 exe和dll两类,其中exe包含Main入口方法可以双击执行,dll ...

  7. 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生

    [转].NET(C#):浅谈程序集清单资源和RESX资源   目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...

  8. Asp.Net Core 单元测试正确姿势

    背景 ASP.NET Core 支持依赖关系注入 (DI) 软件设计模式,并且默认注入了很多服务,具体可以参考 官方文档, 相信只要使用过依赖注入框架的同学,都会对此有不同深入的理解,在此无需赘言. ...

  9. 关于单元测试的思考--Asp.Net Core单元测试最佳实践

    在我们码字过程中,单元测试是必不可少的.但在从业过程中,很多开发者却对单元测试望而却步.有些时候并不是不想写,而是常常会碰到下面这些问题,让开发者放下了码字的脚步: 这个类初始数据太麻烦,你看:new ...

随机推荐

  1. JavaScript 异步编程

    博客地址:https://ainyi.com/96 众所周知,JavaScript 是单线程的,但异步在 js 中很常见,那么简单来介绍一下异步编程 同步编程和异步编程 同步编程,计算机一行一行按顺序 ...

  2. 《Offer一箩筐》2W字总结面试套路14问——不给例子的教程都是耍流氓!!

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」. 如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力! Hi~ 这里是 ...

  3. python列表,字典,元组常用方法和集合

    python 目录 一.列表 列表格式 1.添加 列表取数(按照下标取,下标从0开始) 获取长度 append添加(直接添加) extend添加(分别添加) insert()insert(index, ...

  4. Ajax每隔2秒自动请求服务端刷新页面

    1. window.onload = function () {automatic(); } 2. function automatic(){ //每隔两秒刷新一次页面setTimeout(autom ...

  5. Linux实战(15):Centos 防火墙常见端口命令

    开启命令 firewall-cmd --zone=public --add-port=80/tcp --permanent 关闭命令 firewall-cmd --zone=public --remo ...

  6. 数据库SQL调优的几种方式

    1.创建索引 (1) 要尽量避免全表扫描,首先应考虑在where 及order by涉及的列上建立索引 (2) 在经常需要进行检索的字段上创建索引,一个表中的索引最好不要超过6个 2.避免在索引上使用 ...

  7. Vue开发电子书app

    ebook-app 在根目录下创建vue.config.js文件 module.export = { baseUrl: process.env.NODE_ENV === 'production' ? ...

  8. Autofac的使用

    Autofac的使用 「Autofac简介」 「基本的使用方式」 「如何实现webapi控制器自动注入接口」 一.Autofac简介 ❝ Autofac是实现依赖注入的类库之一,他可以帮助你实现程序的 ...

  9. Mac Catalina 下 gdb codesign问题解决

    在 macOS 上,无法直接使用 gdb 进行 debug. 这是因为 Darwin 内核在你没有特殊权限的情况下,不允许调试其它进程.调试某个进程,意味着你对这个进程有完全的控制权限,所以为了防止被 ...

  10. 小程序开发-iView app的NoticeBar 通告栏修改背景颜色

    NoticeBar 通告栏 这是个比较好用的组件,具体使用方法见 http://inmap.talkingdata.com/wx/index_prod.html#/components/notice- ...