前言

我在使用 AspNetCore 的这段时间内,看了很多开源项目和博客,发现各种 .Net 体系的新技术很多人都有关注和使用,但却很少有人关注测试。

测试是软件生命周期中的一个非常重要的阶段,对于保证软件的可靠性具有极其重要的意义。在应用程序的开发过程中,为了确保它的功能与预期一致,必须对其进行测试。这样做不仅能够确保功能正确执行,同时能够帮助开发人员尽早地发现并改正系统中所存在的缺陷(Bug),从而提高软件的可靠性。测试应该覆盖到软件的所有功能,全面、细致的测试会在很大程度上节省软件开发的成本;反之,不足的测试势必会使软件包含一些未发现的缺陷而投入运行,使用户承担软件缺陷所造成的危险。

从测试所涉及的层次上,分为单元测试、集成测试和系统测试。单元测试是指验证代码段(如方法或函数)功能的测试,通常由开发人员编写相应的测试方法,以验证代码执行后与预期结果是否一致;集成测试用于验证具有依赖关系的多个模块或组件是否能够正常工作;系统测试是对整个系统进行全面测试,以确认系统正常运行并符合需求。

本文主要记录一下单元测试和集成测试。

PS:本文只介绍简单的测试方法,抛砖引玉,更深入的使用可以参考官方文档,其中写得很清楚。

.Net 中的测试

.Net 的测试项目,主要有几种模板

  • MSTest
  • NUnit
  • xUnit

本文选择 xUnit 作为测试项目模板。

单元测试

从测试所涉及的层次上,分为单元测试、集成测试和系统测试。单元测试是指验证代码段(如方法或函数)功能的测试,通常由开发人员编写相应的测试方法,以验证代码执行后与预期结果是否一致;集成测试用于验证具有依赖关系的多个模块或组件是否能够正常工作;系统测试是对整个系统进行全面测试,以确认系统正常运行并符合需求。

  • Arrange:为测试进行准备操作,如设置测试数据、变量和环境等。
  • Act:执行要测试的方法,如调用要测试的函数和方法。
  • Assert:断言测试结果,验证被测试方法的输出是否与预期的结果一致。

最简单的例子

Controller 代码

[ApiController]
public class DemoController : ControllerBase {
[HttpGet("[action]")]
public ApiResponse Test() {
return ApiResponse.Ok("version=2.0");
}
}

单元测试代码

public class DemoTests {
private readonly DemoController _demoController; public DemoTests() {
_demoController = new DemoController();
_demoController.ControllerContext = new ControllerContext {
HttpContext = new DefaultHttpContext()
};
} [Fact]
public void Test_Test() {
var resp = _demoController.Test();
Assert.Equal("version=2.0", resp.Message);
}
}

带参数的 controller

实际开发中,Controller 会使用依赖注入,有很多参数

比如这个 controller ,用到了 EFCore 的 DbContext

public class StudentController : ControllerBase {
private readonly AppDbContext _dbCtx; public StudentController(AppDbContext dbCtx) {
_dbCtx = dbCtx;
}
/// <summary>
/// 学生分数等级
/// </summary>
[HttpGet("[action]")]
public async Task<List<StudentGrades>> StudentScoreGrades() {
return await _dbCtx.StudentGrades.ToListAsync();
}
}

这时候在单元测试里,就得用 mock 对象框架 来实现依赖模拟

这里用的是 Moq 这个库,可以直接 nuget 安装

public class StudentTests {
private readonly StudentController _studentController; public StudentTests() {
var mockOptions = new Mock<DbContextOptions<AppDbContext>>();
var mockDbContext = new Mock<AppDbContext>(mockOptions.Object);
_studentController = new StudentController(mockDbContext.Object) {
ControllerContext = new ControllerContext {
HttpContext = new DefaultHttpContext()
}
};
} [Fact]
public async Task Test_StudentScoreGrades() {
var resp = await _studentController.StudentScoreGrades();
Assert.True(resp.Count > 0);
}
}

PS:实际使用的时候,这个 mock 还是挺麻烦的,所以这些接口还是用后面的集成测试更好。

集成测试

集成测试能够确保应用程序的组件正常工作,包括应用程序支持的基础结构,如数据库和文件系统等。ASP.NET Core提供了用于集成测试的组件,其中包含了用于测试的WebHost和内存测试服务器TestServer。与单元测试不同,这里所有的依赖都是模拟出来的,在集成测试中,应使用与生产环境中一样的真实组件,如数据库和第三方库等。

简单说,单元测试是把所有组件都模拟一遍,集成测试是在真实的系统上进行测试,比如 AspNetCore 开发的接口,集成测试直接使用 HTTP 请求,获取接口数据,然后检查这些返回数据是否符合条件。

开始前需要先安装依赖

dotnet add Microsoft.AspNetCore.Mvc.Testing

公开被测试项目的 Program/Startup 类

集成测试使用 WebApplicationFactory 来启动 AspNetCore 应用

所以需要在被测试的应用里做一点小修改,以便让测试项目可以访问到它的 Program

本文使用的被测试项目是基于 .Net6 的,修改它的 Program.cs ,添加以下代码

public partial class Program { }

使其 Program 类变成共有,让测试项目能够访问到。

官网文档上说还可以修改 .csproj ,添加配置

<ItemGroup>
<InternalsVisibleTo Include="MyTestProject" />
</ItemGroup>

但我试了好像没有效果,所以还是用第一种方法比较方便。

PS:如果是 .Net6 之前的项目,就把 Startup 类改成 public

例子

以刚才的 Student 接口为例

用 HTTP 请求这几个接口,然后判断返回的响应头里是否符合条件。

public class StudentTests : IClassFixture<WebApplicationFactory<Program>> {
private readonly WebApplicationFactory<Program> _factory; public StudentTests(WebApplicationFactory<Program> factory) {
_factory = factory;
} [Theory]
[InlineData("/api/v2/Student/StudentScoreGrades")]
[InlineData("/api/v2/Student/Height")]
[InlineData("/api/v2/Student/Weight")]
public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url) {
var client = _factory.CreateClient();
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
Assert.Equal("application/json; charset=utf-8; ver=2", response.Content.Headers.ContentType?.ToString());
}
}

更多示例

本文只介绍了 WebApi 的集成测试,实际开发可能还会对 MVC、Blazor 等项目进行测试

官方提供了一个实例项目: https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/test/integration-tests/IntegrationTestsSample

里面有很多集成测试的例子,可以参考一下。

运行测试

第一次测试需要先 Build 测试项目

本文使用的 IDE 是 Rider(VS 的话也是大同小异),其中提供了可视化的测试界面

之后写完新的测试直接点击旁边的绿色三角形,就可以单独运行这个新的测试。

参考资料

Asp-Net-Core学习笔记:单元测试和集成测试的更多相关文章

  1. Asp.Net Core学习笔记:入门篇

    Asp.Net Core 学习 基于.Net Core 2.2版本的学习笔记. 常识 像Django那样自动检查代码更新,自动重载服务器(太方便了) dotnet watch run 托管设置 设置项 ...

  2. ASP.NET Core 学习笔记 第一篇 ASP.NET Core初探

    前言 因为工作原因博客断断续续更新,其实在很早以前就有想法做一套关于ASP.NET CORE整体学习度路线,整体来说国内的环境的.NET生态环境还是相对比较严峻的,但是干一行爱一行,还是希望更多人加入 ...

  3. Asp.net Core学习笔记

    之前记在github上的,现在搬运过来 变化还是很大的,感觉和Nodejs有点类似,比如中间件的使用 ,努力学习ing... 优点 不依赖IIS 开源和跨平台 中间件支持 性能优化 无所不在的依赖注入 ...

  4. ASP.NET Core 学习笔记 第三篇 依赖注入框架的使用

    前言 首先感谢小可爱门的支持,写了这个系列的第二篇后,得到了好多人的鼓励,也更加坚定我把这个系列写完的决心,也能更好的督促自己的学习,分享自己的学习成果.还记得上篇文章中最后提及到,假如服务越来越多怎 ...

  5. ASP.NET Core 学习笔记 第四篇 ASP.NET Core 中的配置

    前言 说道配置文件,基本大多数软件为了扩展性.灵活性都会涉及到配置文件,比如之前常见的app.config和web.config.然后再说.NET Core,很多都发生了变化.总体的来说技术在进步,新 ...

  6. ASP.NET Core 学习笔记 第五篇 ASP.NET Core 中的选项

    前言 还记得上一篇文章中所说的配置吗?本篇文章算是上一篇的延续吧.在 .NET Core 中读取配置文件大多数会为配置选项绑定一个POCO(Plain Old CLR Object)对象,并通过依赖注 ...

  7. asp.net.core学习笔记1:swagger的使用和webapi接收Jobject对象

    环境:asp.net.core 3.1 (一觉醒来官方已经不推荐3.0了,于是没有任何core经验,也只能开始了3.1的开发学习) 由于现有项目前后端分离.微服务化日趋流行,所以上手不采用web应用( ...

  8. Asp.net core 学习笔记 ( Data protection )

    参考 : http://www.cnblogs.com/xishuai/p/aspnet-5-identity-part-one.html http://cnblogs.com/xishuai/p/a ...

  9. Asp.net core 学习笔记 SignalR

    refer : https://kimsereyblog.blogspot.com/2018/07/signalr-with-asp-net-core.html https://github.com/ ...

  10. Asp.net core (学习笔记 路由和语言 route & language)

    https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-2.1 https://doc ...

随机推荐

  1. Shell在日常工作中的应用实践

    作者:京东物流 李光新 1 Shell可以帮我们做什么 作为一名测试开发工程师,在与linux服务器交互过程中,大都遇到过以下这些问题: •一次申请多台服务器,多台服务器需要安装相同软件,配置相同的环 ...

  2. 【故障补牢】贪吃的 Bing 爬虫,限量供应的应对措施

    相对于[故障公告],[故障补牢]分享的是园子在发生故障后采取的亡羊补牢措施. 在上次被微软 Bing 爬宕机后(详见 [故障公告]被放出的 Bing 爬虫,又被爬宕机的园子),我们采取了2个应对措施, ...

  3. 2021-12-18:找到字符串中所有字母异位词。 给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成

    2021-12-18:找到字符串中所有字母异位词. 给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引.不考虑答案输出的顺序. 异位词 指由相同字母重排列形成 ...

  4. SICP:元循环求值器(Python实现)

    求值器完整实现代码我已经上传到了GitHub仓库:TinySCM,感兴趣的童鞋可以前往查看.这里顺便强烈推荐UC Berkeley的同名课程CS 61A. 在这个层次结构的最底层是对象语言.对象语言只 ...

  5. ET介绍—— 一切皆实体的设计

    一切皆实体 目前十分流行ECS设计,主要是守望先锋的成功,引爆了这种技术.守望先锋采用了状态帧这种网络技术,客户端会进行预测,预测不准需要进行回滚,由于组件式的设计,回滚可以只回滚某些组件即可.ECS ...

  6. .NET Core 程序实现 Windows 系统 Development、Staging、Production 三种环境的无感部署

    〇.前言 日常开发中,程序的环境切换是相当频繁的了,如果不同环境中的某些参数不同,那就需要每次编辑之前手动进行修改,比较麻烦,效率低下. 本文将以 .NET Core WebAPI 项目的配置方法为例 ...

  7. R 语言中的高级图像处理包

    最新的 magick 包是为能够在 R 中更现代化.简单化高质量图像处理而进行的一次努力.该包封装了目前最强大的开源图片处理库 ImageMagick STL . ImageMagick 库具有大量功 ...

  8. sqlmap工具学习

    tryhackme:sqlmap github:https://github.com/sqlmapproject/sqlmap kali集成 参数介绍 sqlmap -h ___ __H__ ___ ...

  9. Vue自定义指令-让你的业务开发更简单

    1.使用场景 在日常开发中,我们会将重复代码抽象为一个函数或者组件,然后在需要时调用或者引入.但是,对于某些功能,这种方法可能不够优雅或者不够灵活.例如,我们可能需要在DOM元素上添加一些自定义属性或 ...

  10. JS基础语法(一)

    javascript简介 javascrpit是是一种轻量级的编程语言,常用于web前端开发.另外js还可以用来写node.js类型的服务和工具,在测试web项目的时候需要了解. 变量 js定义变量有 ...