什么是单元测试,如何去写一个单元测试

agate


相信单元测试是属于那种没有用过也听过的技术(如果你是大佬,听过也用过,欢迎提出宝贵的意见🧎‍♀️🧎‍♂️)。那么到底什么是单元测试,单元测试在实际项目开发中能给我们带来什么样的好处?我们站在前端开发的角度一起来聊一聊单元测试。

📚(一)什么是单元测试

📢单元测试概念

单元测试是指对软件中最小可测单元进行检查和验证;c语言中单元指一个函数,java中指一个类。图形化软件中可以指一个窗口或者一个菜单。总的来说,单元就是认为规定最小的被测试模块。
这个便是对百度百科上对单元测试的介绍,那么对于我们前端来说单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

大多数单元测试包括四个主体:
  • 测试套件describe、
  • 测试用例it、
  • 判定条件expect、
  • 断言结果toEqual。
什么不是单元测试

在了解了什么是单元测试的基础上,那么什么不是单元测试呢?在《修改代码艺术》一书上有这样的介绍:

  • 需要访问数据库的测试不是单元测试
  • 需要访问网络的测试不是单元测试
  • 需要访问文件系统的测试不是单元测试

以上便是对单元测试概念的简单介绍,那么为什么要使用单元测试,单元测试有什么优势,不考虑回报的程序员不是好的程序员。


📚(二)单元测试对我们开发程序有什么好处

  • 首先是一个前端单元测试的根本性原由:JavaScript 是动态语言,缺少类型检查,编译期间无法定位到错误; JavaScript 宿主的兼容性问题。比如 DOM 操作在不同浏览器上的表现。

  • 正确性:测试可以验证代码的正确性,在上线前做到心里有底。

  • 自动化:当然手工也可以测试,通过console可以打印出内部信息,但是这是一次性的事情,下次测试还需要从头来过,效率不能得到保证。通过编写测试用例,可以做到一次编写,多次运行。

  • 解释性:测试用例用于测试接口、模块的重要性,那么在测试用例中就会涉及如何使用这些API。其他开发人员如果要使用这些API,那阅读测试用例是一种很好地途径,有时比文档说明更清晰。

  • 驱动开发,指导设计:代码被测试的前提是代码本身的可测试性,那么要保证代码的可测试性,就需要在开发中注意API的设计,TDD将测试前移就是起到这么一个作用。

  • 保证重构:互联网行业产品迭代速度很快,迭代后必然存在代码重构的过程,那怎么才能保证重构后代码的质量呢?有测试用例做后盾,就可以大胆的进行重构。

我们知道 高覆盖率的单元测试,可以保证每次上线bug率大大降低,也是代码重构的基础。很多老项目,开发人员离职、新接手的人员不敢重构,慢慢称为团队负担、又不能下线,就是因为没有单元测试,改一点都怕出现不可测的bug。简单来说,也可以概括为以下几点

  1. 提高代码质量
  2. 减少bug,快速定位bug
  3. 放心地修改、重构
  4. 单元测试不但会使你的工作完成得更轻松。而且会令你的设计会变得更好,甚至大大减少你花在 调试上面的时间

📚(三)如何编写单元测试用例

如何编写单元测试用例,单元测试用例的原则是什么:

  • 测试代码时,只考虑测试,不考虑内部实现;
  • 数据尽量模拟现实,越靠近现实越好,
  • 充分考虑数据的边界条件下·
  • 对重点、复杂、核心代码、重点测试
  • 利用AOP(面向切面编程),减少测试代码,避免无用功能
  • 测试、功能开发相结合,有利于设计和代码重构

🔎插一个小知识点:那么这里提到的AOP是什么意思,AOP是Aspect Oriented Program的首字母缩写意思是面向切面编程,这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

📌一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。

再简单了解了单元测试之后我们将其带入到我们实际项目开发中,来尝试一下


📚(四)组件化后,组件哪部分最具测试价值?(以React为例)

image.png

1. Component

Component 应着重关注render以及副作用,同时业务逻辑的处理过程,都应该尽量提取到Hooks和Utils文件中。因此,对于Component的测试,我们完全可以将重心主要放在以下这两方面问题上:

  • 组件是否正常渲染了?
  • 组件副作用是否正常处理了?
2. Hooks

如何测试React Hooks,社区目前已有相对成熟的解决方案,即@testing-library/react-hooks + react-test-renderer[2]。通过这两个依赖,开发人员可以很轻松的mock出Hooks执行所依赖的环境,把store的数据当作hooks的输入,关注在hooks内的业务逻辑,即可把Hooks当作纯方法(Pure Function)来进行测试。

3. Redux

对于Redux,如果项目在使用 Redux Toolkit 的话,事情会简单很多,开发人员只需要关注Dispatch的Actions即可。但如果Actions和Reducer是分开编写,则需要针对性处理

4. Service

不同项目或团队对Service的定义各不相同,这里我们要聊的主要指负责处理HTTP请求的request和response,以及相应的异常处理的数据层。Service主要的功能是对接Action,因而理想情况下Service只需要包含与API通信的代码,这种情况下,UT可有可无。但一些场景下,如果项目中没有使用BFF承担数据处理的角色,后端也没能提供完全符合前端数据结构需求的接口时,不可避免的,开发人员需要在此处完善数据处理的逻辑,以便获取清洗或聚合后的数据,因而这种情况下,UT覆盖是非常有必要的。

5. Utils/Helpers

Utils/Helpers主要包含以下几类类型:
数据结构的转化,各种convert工具函数
数据结构的处理,比如数据提取、合并压缩、整理工具函数
公共的工具函数
根据我们目前的项目习惯,当一段逻辑需要在Utils/Helpers中实现时,那么它一定是纯函数,其中多数情况又会包含一定程度的数据处理逻辑,所以基本都需要UT覆盖

在了解了项目组件哪些部分最具有测试价值之后,我们就要上手了,跃跃欲试中🤸‍♀️🤸‍♂️


📚(五)如何让我们的测试用例更易编写、维护?

举个例子💁‍🌰,先看代码,看不看得懂不重要🧎‍♀️,我们先来了解一下

// production code
const computeTotalAmount = (products) => {
   
  return products.reduce((total, product) => total + product.price, 0); 
}

// testing code
it('should return summed up total amount 1000 when there are three products priced 200, 300, 500', () => {
   
  // given - 准备数据
  const products = [
    {
    name: 'nike', price: 200 },
    {
    name: 'adidas', price: 300 },
    {
    name: 'lining'
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值