首页 > 其他分享 >NetCore学习笔记:单元测试和集成测试

NetCore学习笔记:单元测试和集成测试

时间:2023-10-07 12:33:42浏览次数:44  
标签:集成 测试项目 NetCore 单元测试 笔记 测试 new public

前言#

我在使用 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 的话也是大同小异),其中提供了可视化的测试界面

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

参考资料#

 

【出处】:https://www.cnblogs.com/deali/p/17559685.html

标签:集成,测试项目,NetCore,单元测试,笔记,测试,new,public
From: https://www.cnblogs.com/mq0036/p/17746006.html

相关文章

  • Java 学习笔记
    Java学习笔记dos环境下(Windows即cmd)的Java命令先用javac文件名.java;命令,编译java文件,生成一个后缀为class、名与类名相同的文件。再用java类名命令,执行文件。当类名前的修饰符为public时,类名必须和源文件名一致。并且以上操作不能执行带package的java文......
  • 如何在ipad上对pdf做笔记
    在iPad上做笔记,您可以按照以下步骤:1.选择一个文本编辑应用程序,如GoogleDocs、GoodNotes、Notability或OneNote。2.打开文本编辑器应用程序,并在其中输入要记录的文本。3.点击文本编辑器应用程序的“标记”(菜单)图标。4.从弹出的菜单中,选择“注释”选项。5.在注释选项卡上,点击“......
  • JAVA学习笔记1
    private封装extends继承编译类型是爷爷多态整个继承过程构造器必须首行引用爷爷的构造器(用super)点击查看代码packagecom.hspstudy.Test1;publicclassExtend_{publicstaticvoidmain(String[]a){GraFathergraFather=newGraFather("勤才",......
  • 【python笔记】虚拟环境
    1.虚拟环境的建立python-mvenv<虚拟环境名>#例如:python-mvenvmy_venv2.虚拟环境的激活与去激活激活cd到虚拟环境文件夹下的Scripts,在终端执行activate去激活cd到虚拟环境文件夹下的Scripts,在终端执行deactivate.bat3.在虚拟环境中下载依赖python-mpipin......
  • JS异步笔记
    Promise最早接触异步是在.net中,当时还是比较流行使用基于控件的BackgroundWorker,其自身通过子线程的方式来异步处理一些情况,并且封装了一些功能与主线程通信。后来,开始使用Thread,再后来,因为Thread的性能与生成数量的不可控,使用了ThreadPool,再后来,出现了Task,随后async、await如发......
  • 混淆技术研究笔记(六)如何基于yGuard实现?
    确定参考<adjust>作为入口后,就需要详细了解这部分代码的逻辑。需要看yguard源码了,你会如何阅读一个完全不了解的源码?我通常的策略都是找一个目标,添加代码依赖,写好demo,debug跟踪代码看。如果漫无目的的看,很难串起来整个流程,范围太大也容易迷失。先在配置中增加<adjust>配置:......
  • 【爬虫实战】用python爬小红书某话题的笔记,以#杭州亚运会#为例
    目录一、爬取目标二、爬虫代码讲解2.1分析过程2.2爬虫代码三、演示视频四、获取完整代码一、爬取目标您好!我是@马哥python说,一名10年程序猿。最近的亚运会大家都看了吗。除了振奋人心,还主打一个爱憎分明(主要针对小日子和韩国),看了的小伙伴都懂得!我用python爬取了小红书上#杭......
  • 《流畅的Python》 读书笔记 231007(第二章第一部分)
    第2章数据结构ABC语言是Python的爸爸~很多点子在现在看来都很有Python风格:序列的泛型操作、内置的元组和映射类型、用缩进来架构的源码、无需变量声明的强类型不管是哪种数据结构,字符串、列表、字节序列、数组、XML元素,抑或是数据库查询结果,它们都共用一套丰富的操作:迭......
  • 组合数学学习/复习笔记
    模板(前置芝士)P1226【模板】快速幂|取余运算目的:顾名思义,快速求解乘方。实现:挺好写的。题目传送门代码P3811【模板】乘法逆元开longlong!!定义:若\(a*x\equiv1\pmodb\),且\(a\)与\(b\)互质,那么就能定义\(x\)是\(a\)在模\(p\)意义下的逆元,记为\(a^{......
  • 【学习笔记】(13) 平衡树——记住不的板子
    TreapSplay无旋Treap——fhqtreap简介就是没有旋转操作的Treap,一些性质什么的都跟Treap类似。算法介绍(1)merge(x,y)将两棵“有序”(x中元素的权值最大值小于y中元素权值最小值)的Treap合并成一棵。intch[N][2],sz[N],pri[N],val[N];//val为权值,pri为优先级,sz......