.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. 小程序开发-6个优秀的UI组件库

    微信小程序开发,当原生的控件不能满足我们时,可以尝试下面几个比较优秀的组件库. 1. WeUI WXSS WeUI WXSS是腾讯官方UI组件库WeUI的小程序版,提供了跟微信界面风格一致的用户体验. ...

  2. selenuim中18种定位方式

    18种定位方式=8种单数形式+8种复数形式+2种底层方案 单数可以确定唯一,复数无法确定: 单数形式定位,返回的是一个元素,复数形式,返回的是一个列表,返回的是当前页面所有符合要求的元素,没有意义 一 ...

  3. PHP学习路线图(转)

    PHP学习路线图 在网上很多人公布了太多的PHP学习路线图,本人在互联网公司工作十余年,也带了很多PHP入门的新手,将他们的一些问题和学习路线图为大家整理出来,希望很多小白少走弯路. 一. 网上某些错 ...

  4. TDengine常见问题解答(FAQ)

    1. TDengine2.0之前的版本升级到2.0及以上的版本应该注意什么?☆☆☆ 2.0版本在之前版本的基础上,进行了完全的重构,配置文件和数据文件是不兼容的.在升级之前务必进行如下操作: 删除配置 ...

  5. 在windows下使用pip安装python包遇到缺失stdint.h文件的错误

    今天在windows上使用pip安装一个python包python-lzf时遇到如下的错误: fatal error C1083: Cannot open include file: 'stdint. ...

  6. Java审计之文件操作漏洞

    Java审计之文件操作漏洞篇 0x00 前言 本篇内容打算把Java审计中会遇到的一些文件操作的漏洞,都给叙述一遍.比如一些任意文件上传,文件下载,文件读取,文件删除,这些操作文件的漏洞. 0x01 ...

  7. 利用Python爬取疫情数据并使用可视化工具展示

    import requests, json from pyecharts.charts import Map, Page, Pie, Bar from pyecharts import options ...

  8. 802.1X 账号密码+设备信息双重认证

    名词解释 802.1X: IEEE802 LAN/WAN 委员会为解决无线局域网网络安全问题,提出了 802.1X 协议.后来,802.1X协议作为局域网端口的一个普通接入控制机制在以太网中被广泛应用 ...

  9. 普转提Day1

    T1 给定一个长度为N的序列,去掉其中连续的一部分使得剩下的部分没有重复元素. 很显然可以发现去掉的一部分只有三种情况:开头.中间.最后. 那么我们只需要枚举Hash就可以了.复杂度O(N^2). 不 ...

  10. Harmony OS 开发避坑指南——DevEco Device Tool 安装配置

    Harmony OS 开发指南--DevEco Device Tool 安装配置 本文介绍如何在Windows主机上安装DevEco Device Tool工具. 坑点总结: 国内部分网络环境下,安装 ...