本文演示Util应用框架开发的项目中如何编写集成测试.

准备

完成 Web Api 快速入门,本文将在之前生成的示例项目上讲解集成测试的开发.

测试概述

自动化测试对于Util应用框架的开发非常重要,它能保证基础功能的稳定性.

对于使用 Util 开发的业务项目,自动化测试不是必须的,但掌握它可能很有用.

如果你使用 Util 开发 Web API,可能会使用 Swagger 进行测试.

将 Swagger 提供给前端人员是合适的,但后端人员使用它却不够省力.

原因很简单,使用 Swagger 测试 API,需要设置一堆参数,这些参数无法保存,每次运行都需要设置.

使用 .Net 自动化测试会更加方便,并且现在开发集成测试的成本很低.

专业测试的分类非常细,下面简要讨论自动化功能测试.

测试分类

这里粗略的对自动化功能测试概括为两类:

  • 单元测试

    • 隔绝外部依赖,仅测试自身的某些功能.
    • 如果需要访问外部依赖,通过定义抽象接口的方式使用,不能直接引用.
    • 在 Util 分层架构中,一般对领域层实体,值对象,领域服务实施单元测试.
  • 集成测试

    • 直接访问外部依赖,对关联的所有类型进行测试.
    • 在 Util 分层架构中,一般对基础设施层仓储,应用层应用服务和API接口进行集成测试.

测试的好处

修改任何一行业务代码,都有可能影响之前的逻辑.

自动化测试基于对业务功能的预期反应,如果预期未发生变化,但你的代码逻辑出现变化,就能帮你拦截这个错误.

测试的弊端

  • 除了开发自动化测试本身的成本以外,更大的成本在于维护.

  • 每当需求变更,需要删除已经过时的测试,开发新的测试,修改之前的测试以符合当前预期.

测试编写条件

自动化测试的语法非常简单,但并不是掌握了测试语法就能编写出有效的测试.

编写单元测试需要开发人员有一定抽象思维,能够抽象和隔离依赖,还需要了解一些单元测试技巧.

不要在公司全面推行单元测试,容易变成形式主义,仅让团队核心骨干对高价值业务模块编写单元测试.

集成测试则要简单得多,只要懂得测试语法就可以编写.

集成测试由于直接访问外部依赖,运行缓慢,而且任何环节变更都可能导致测试失败,所以不宜大量编写.

你是否需要它?

  • 如果你仅负责编写 Web API ,手头没有现成的UI进行测试,编写集成测试比使用 Swagger 省力.

  • 如果你没有打算持续维护这些测试,不要编写它们,那只会浪费时间.

  • 如果你的团队精力有限,无法维护大量的测试,可以仅对高业务价值的模块编写测试.

测试框架选型

  • 测试框架

  • 模拟框架

    • Moq - 为依赖服务接口创建模拟实现.
  • 数据伪造框架

Util集成测试开发入门

单元测试用于测试复杂的业务逻辑,由于快速入门Demo仅包含简单CRUD操作,无法演示单元测试的用法.

下面介绍在Util项目中如何开发集成测试.

运行示例项目

打开示例项目解决方案 Demo.sln,查看 test 子目录,它包含4个测试项目.

生成的测试项目已经将环境配置完成,你可以直接开始编写测试.

Demo.Domain.Tests 是领域层的单元测试项目,如果你不需要编写单元测试,直接删掉它.

其它三个项目用于集成测试,下面分别介绍.

数据访问层集成测试

Demo.Data.SqlServer.Tests 是数据访问层 Sql Server 集成测试项目.

如果支持多种数据库,则每种数据库应包含一个数据访问层集成测试项目.

数据访问层测试的重点是仓储.

打开 StudentRepositoryTest 学生仓储测试类.

在 StudentRepositoryTest 的构造方法中注入了依赖接口 IDemoUnitOfWork 和 IStudentRepository.

Util 代码生成模板默认会创建 TestAddAsync 方法,它用于测试添加实体.

该测试使用伪数据生成框架创建学生实体,并通过仓储保存到数据库.

不宜编写过多的CRUD集成测试,通常保留一两个即可.

它们的作用不是测试逻辑,而是迅速识别开发环境是否通畅.

特别是当你升级框架或类库时,有几个简单的集成测试非常有用.

运行数据访问层集成测试

打开 appsettings.Development.json 配置文件,检查连接字符串是否正确.

{
"ConnectionStrings": {
"connection": "Server=.;Database=Demo.Data.Test;uid=sa;pwd=Pass@word;TrustServerCertificate=true"
}
}

Demo示例的数据访问层测试数据库名为 Demo.Data.Test ,运行测试时, EntityFrameworkCore 会自动创建和删除测试数据库,非常方便.

使用 Visual Studio 运行测试

右键单击 TestAddAsync 方法,弹出菜单选择 运行测试.

弹出 测试资源管理器 窗口,并自动运行测试.

使用 Resharper 运行测试

如果你安装了Resharper, VS中的测试方法会在左侧显示测试图标,如下图所示.

点击 Run 按钮,运行测试.

应用层集成测试

应用层集成测试包含 Demo.Application.TestsDemo.Api.Tests 两个测试项目.

应用服务集成测试

Demo.Application.Tests 侧重于测试应用服务,并且没有Asp.Net Core相关环境干扰.

对于普通项目,大多业务逻辑会写到应用服务中, 所以它是比较理想的测试场所.

如果你不想维护太多测试项目,那么仅保留应用服务集成测试即可.

打开 StudentServiceTest 测试类,代码生成模板默认也创建了一个 TestCreateAsync 测试方法.

/// <summary>
/// 学生服务测试
/// </summary>
public class StudentServiceTest {
/// <summary>
/// 学生服务
/// </summary>
private readonly IStudentService _service; /// <summary>
/// 测试初始化
/// </summary>
public StudentServiceTest( IStudentService service ) {
_service = service;
} /// <summary>
/// 测试创建
/// </summary>
[Fact]
public async Task TestCreateAsync() {
//创建
var dto = StudentDtoFakeService.GetStudentDto();
var id = await _service.CreateAsync( dto ); //验证
var result = await _service.GetByIdAsync( id );
Assert.NotNull( result );
Assert.Equal( id, result.Id );
}
}

StudentServiceTest 从构造方法注入了 IStudentService 应用服务接口.

使用伪数据生成框架创建DTO,并调用服务保存数据.

Web Api集成测试

Demo.Api.Tests 用于测试 Web Api控制器,它的测试环境要复杂一些.

打开 StudentControllerTest 测试类.

/// <summary>
/// 学生控制器测试
/// </summary>
public class StudentControllerTest : TestBase {
/// <summary>
/// 输出工具
/// </summary>
private readonly ITestOutputHelper _testOutputHelper; /// <summary>
/// 测试初始化
/// </summary>
public StudentControllerTest( ITestOutputHelperAccessor testOutputHelperAccessor,IHttpClient client ) : base( client ){
_testOutputHelper = testOutputHelperAccessor.Output;
} /// <summary>
/// 测试创建
/// </summary>
[Fact]
public async Task TestCreateAsync() {
//服务地址
var url = "/api/student"; //创建实体
var dto = StudentDtoFakeService.GetStudentDto();
var result = await PostAsync<StudentDto>( url, dto ); //验证
Assert.Equal( StateCode.Ok, result.Code );
Assert.NotEmpty( result.Data.Id );
_testOutputHelper.WriteLine( Json.ToJson( result ) );
}
}

Web Api的测试需要发送请求给控制器,并接收响应结果,所以需要一个Http客户端.

StudentControllerTest 构造方法注入 Util Http客户端接口,将将接口传递给 TestBase 基类.

TestBase 进一步封装对 GET, POST ,PUT ,DELETE 操作请求,以简化测试的编写.

默认生成的 TestCreateAsync 方法,使用伪数据生成框架创建DTO, 并使用 Post 请求指定 Url.

Web Api 控制器返回 Util 约定的特定消息.

对于开发 Web Api, 该集成测试能更好的反映与前端的交互.

运行 Web Api集成测试,如下所示.

Util应用框架快速入门(4) - 集成测试开发入门的更多相关文章

  1. 【python】 web开发入门

    进入Web开发 现在你完成了Python忍者训练,准备深入Ptyhon的Web开发,但现在的问题是有很多的框架,从中选择最好的框架非常困难,但从初学者的角度出发,Flask基本Web框架将非常适合We ...

  2. [译]:Xamarin.Android开发入门——Hello,Android快速上手

    返回索引目录 原文链接:Hello, Android_Quickstart. 译文链接:Xamarin.Android开发入门--Hello,Android快速上手 本部分介绍利用Xamarin开发A ...

  3. 使用 CodeIgniter 框架快速开发 PHP 应用(七)

    原文:使用 CodeIgniter 框架快速开发 PHP 应用(七) CodeIgniter 和对象这是玩家章节.它讲述的是 CodeIgniter 的工作原理,也就是揭开CI头上'神秘的面纱'.如果 ...

  4. 使用 CodeIgniter 框架快速开发 PHP 应用(六)

    原文:使用 CodeIgniter 框架快速开发 PHP 应用(六) 简化使用 Session 和安全理论说得够多了! 现在让我们开始写我们自己的应用. 在这一章里,我们将会大致描述一下我们要建立的一 ...

  5. 使用 CodeIgniter 框架快速开发 PHP 应用(五)

    原文:使用 CodeIgniter 框架快速开发 PHP 应用(五) 简化 HTML 页面和表格设计这一章介绍了又一个节约你的时间而且使你的代码更具安全性和逻辑性的领域.第一,我们将会介绍创建视图的各 ...

  6. 使用 CodeIgniter 框架快速开发 PHP 应用(四)

    原文:使用 CodeIgniter 框架快速开发 PHP 应用(四) 使用 CI 简化数据库开发你学习CI 是因为你想要使编程更容易和更有生产力.这一章讲述CI的Active Record类. 如果C ...

  7. 使用 CodeIgniter 框架快速开发 PHP 应用(二)

    原文:使用 CodeIgniter 框架快速开发 PHP 应用(二) 二分钟: 建立一个 CodeIgniter 网站用CI建一个网站很容易. 这一章很短,解释了用CI制作网站时发生了些什么,哪些文件 ...

  8. 使用 CodeIgniter 框架快速开发 PHP 应用(三)

    原文:使用 CodeIgniter 框架快速开发 PHP 应用(三) 分析网站结构既然我们已经安装 CI ,我们开始了解它如何工作.读者已经知道 CI 实现了MVC式样. 通过对目录和文件的内容进行分 ...

  9. 使用 CodeIgniter 框架快速开发 PHP 应用(一)

    原文:使用 CodeIgniter 框架快速开发 PHP 应用(一) 对 CodeIgniter 的介绍大多数PHPer都想写出运行状态良好的应用程序,而且希望尽可能做得简单且不费事.这篇文章是有关 ...

  10. Python云端系统开发入门——框架基础

    Django框架基础 这是我学习北京理工大学嵩天老师的<Python云端系统开发入门>课程的笔记,在此我特别感谢老师的精彩讲解和对我的引导. 1.Django简介与安装 Django是一个 ...

随机推荐

  1. 使用Stable Diffusion制作AI数字人视频的简明教程

    基本方法 搞一张照片,搞一段语音,合成照片和语音,同时让照片中的人物动起来,特别是头.眼睛和嘴. 语音合成 语音合成的方法很多,也比较成熟了,大家可以选择自己方便的,直接录音也可以,只要能生成一个语音 ...

  2. DevOps|服务治理与服务保障实践指南

    朱晋君@君哥聊技术 我自己为了消化里边的内容,整理了一个脑图,希望对你有帮助. 凌晨四点被公司的监控告警叫醒了,告警的原因是生产环境跑批任务发生故障.即刻起床处理故障,但还是花了不少时间才解决. 这次 ...

  3. sql-lab通关

    page1-less1-22 联合查询 第一关 发现是有回显的,且传入的参数是通过'1'包裹的,所以我们的payload,如下 测试列数 ?id=1' order by 3 --+ //超过第一条语句 ...

  4. Django: AttributeError: 'str' object has no attribute 'decode'

    Django安装Mysql驱动 pip install PyMySQL 在Django的工程同名子目录的__init__.py文件中添加如下语句 from pymysql import install ...

  5. 一条命令突破Windows限制,暂定更新时间至3000天

    在系统界面上最长也就只能延期 35 天,而且 35 天以后一定要更新了才能继续暂停.不过,我找到了一段能延长暂停时间的代码 reg add "HKEY_LOCAL_MACHINE\SOFTW ...

  6. 语音合成技术3:HierVST: Hierarchical Adaptive Zero-shot Voice Style Transfer

    HierVST: 分层自适应零样本语音风格转换 摘要: 尽管语音风格转换(VST)领域取得了快速进展,但最近的零样本VST系统仍然缺乏将新的说话者的语音风格进行转换的能力.在本文中,我们提出了Hier ...

  7. [kubernetes]集群中部署CoreDNS服务

    前言 从k8s 1.11版本开始,k8s集群的dns服务由CoreDNS提供.之前已经使用二进制文件部署了一个三master三node的k8s集群,现在需要在集群内部部署DNS服务. 环境信息 IP ...

  8. fastapi之helloworld

    简介 以下简介来自官网描述: FastAPI是一个用于构建API的现代.快速(高性能)的web框架,使用Python3.6+并基于标准的Python类型提示. 关键特性: 快速:可与NodeJS和Go ...

  9. 使用canvas(2d)+js实现一个简单的傅里叶级数绘制方波图

    先看效果 查看页面右下角,嘿嘿 简要说明 创建具有不同半径与角速度的圆集合:(截图中展现的效果为5个,代码是30个,运行后效果会不同) const getCircles = (N = 10) => ...

  10. 让C#调用vue组件里的方法

    前言:web页面开发时采用的是vue开发的,后台语言是C# 需求:后台需要通过浏览器调用vue组件的方法 c# 可以调用xxx.html 中的script引用的js中定义的方法是可以调用的, 之前c# ...