对单元测试的思考(稳定性建设)

单测是很常见的技术的名词,但背后的逻辑和原理你是否清楚,让我们一起review一下。

1. 单测是什么?🤔

单测是单元测试,主要是测试一个最小逻辑块。比如一个函数、一个react、vue 组件。

2.为什么要写单测?🤔

这里有短期和长远,两个方面做打算:

短期:

希望开发者在开发过程中,就要想清楚多种case的情况,来检测这个最小单元的可靠性

举个例:

describe('test getUriEnd', () => {
  it('case1', async () => {
    const ret = getUriEnd(...);
    expect(ret).toBe('...');
  });

  it('case2', async () => {
    const ret = getUriEnd(...);
    expect(ret).toBe('...');
  });

  it('case3', async () => {
    const ret = getUriEnd('');
    expect(ret).toBe('error');
  });

  it('case4', async () => {
    const ret = getUriEnd([]);
    expect(ret).toBe('error');
  });
});

长期:

从长期的维护角度来看的话,各个最小单元都是可能有被修改的风险。如果有完整的单侧的case,是可以保证:迭代、修改后的功能单元,不是会出现一些边缘问题

并且长期来看:单侧也可以作为一个这个功能单元的使用说明书的作用。帮助开发更好的理解功能。

3.单测是跑在什么环境的?🤔

是跑在node环境的。

那为什么可以测试一些和浏览器环境相关的操作?比如:document.createElement

test('use jsdom in this test file', () => {  
    const element = document.createElement('div');  
    expect(element).not.toBeNull();  
});

要设置当前单测运行的环境,否则上面的单测会报错,因为单测是跑在node环境的(我这里以jest为例)

在jest内,需要配置 testEnvironment: ‘jsdom’ (不主动配置的话,这里是node,代表node环境)。

jest文档:jestjs.io/zh-Hans/doc…

那jest是怎么做到模拟浏览器环境的?

jest用的是jsdom:github.com/jsdom/jsdom (jsdom模拟浏览器环境的原理,可以参考jsdom的官网)。

本质还是运行在node内,只不过用了jsdom来模拟浏览器环境。

4.单测的原理是什么?🤔

原理是:

给最小单元:提供运行时环境(node或浏览器环境,且包含对应依赖)。让这个最小单元在这个环境里面去执行,跑case,检验是否符合预期。

5.单测中需要注意哪些问题?为什么单测会引发这些问题?🤔

单测的核心问题就是准备环境,为了让单测可以正常执行,我们需要准备好上下游环境,还有依赖环境。

比如你要测试一个vue组件的props,那么你就需要为他准备好相关的vue实例,往单测的node环境里面注入Vue,例如 import { shallowMount } from ‘@vue/test-utils’

import { shallowMount } from '@vue/test-utils'
import Drawer from '@/components/common/drawer.vue'

test('test drawer', () => {
  const wrapper = shallowMount(Drawer, {
    propsData: {
      direction: 'top',
      show: true,
      canConfirm: true,
      title: 'my drawer',
      leftText: 'left text',
      rightText: 'right text'
    }
  })
  const text = wrapper.text()
  expect(text).toContain('my drawer')
  expect(text).toContain('left text')
  expect(wrapper.get('.drawer-top')).not.toBeNull()

  wrapper.find('.header-right').trigger('click')
  wrapper.find('.header-left').trigger('click')

  expect(wrapper.emitted()).toHaveProperty('onConfirm')
  expect(wrapper.emitted()).toHaveProperty('onCancel')
})

如果涉及到路由相关的话,那么还需要准备路由相关依赖。

有些依赖实在不好准备的话,需要设置mock(比如依赖一个额外的SDK,但这个SDK没法在node里面的跑)。

import { mount, createLocalVue } from '@vue/test-utils'
import Register from '@/components/xxx.vue'
import Vuex from 'vuex'

const localVue = createLocalVue()
localVue.use(Vuex)

jest.mock('@xxx/sdk.css', () => { // 这里设mock
  return ''
})

describe('test register', () => {
  const store = new Vuex.Store({
    actions: {},
    state: {
      form: {
        formData: {
          selectCountry: '',
        },
      },
    },
    getters: {
      'user/userCountry': () => ''
    },
  })
  const wrapper = mount(Register, {
    store,
    localVue,
    mocks: { // 这里也可以设mock
      $route: {
        query: {}
      }
    }
  })
  it('should vm', () => {
    expect(wrapper.vm).toBeTruthy()
  })

  it('should xxx', () => {
    expect(wrapper.find('#xxxdom').exists()).toBeTruthy()
  })
})

如果涉及到接口请求的话,接口是下游rpc或者是服务发现的话,那么单侧环境是肯定调不通的。因为有环境隔离。这种情况下就只能Mock数据了。

为什么单测会引发这些问题,感觉这么麻烦?

因为单测是运行在node环境里跑,相当于本地,本地去掉下游rpc服务或走服务发现,本来就是不行的,因为环境隔离。本地加代理,也只能调通测试环境rpc服务

单测环境是一个“干净”的环境,不主动准备的话 是没有node_modules的。如果你的测试单元 有各种依赖,单测环境肯定是没有的,除非你自己准备好 或者 mock模拟/代理掉

6.哪些场景适合写单测?🤔

首先写单测肯定是有成本的,我个人认为,非常重要的toC项目才有必要写单测;

先覆盖核心功能;

功能单一的函数或组件是很适合写单测的。

7.怎么定义一个单测写的好不好?🤔

单纯不考虑成本的话,那么一个单测的好坏应该是看这一个单元的功能覆盖率 + 边界case的覆盖情况。越多越好。

8.对单测成本和收益的思考?🤔

团队内的任何决策都是有成本的,单测也不例外,需了解成本和收益后,再考虑在团队内推进。

单测成本:

主要是开发成本:写单测、code review,边界case覆盖。

单测收益:

未来的维护成本会更低,项目质量、稳定性更好。

有利于倒逼开发写出高质量的代码、关注稳定性。

我个人思考,还是想低成本得到所有好处(“我都要”):选择性写单测

个人认为写单测的条件:toC且核心流程 + 很难自测的部分(边界case) + e2e或快照测试很难覆盖到的部分

某些业务场景,后续肯定也是要自测的话,那这部分相关的可以不用写单测。

e2e或快照测试,能覆盖到的,可以不写单测。

行动吧,在路上总比一直观望的要好,未来的你肯定会感谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入群:1007119548,里面有各种测试开发资料和技术可以一起交流哦。

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取 【保证100%免费】

在这里插入图片描述

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。在这里插入图片描述
在这里插入图片描述在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/423097.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《Large Language Models for Generative Information Extraction: A Survey》阅读笔录

论文地址:Large Language Models for Generative Information Extraction: A Survey 前言 映像中,比较早地使用“大模型“”进行信息抽取的一篇论文是2022年发表的《Unified Structure Generation for Universal Information Extraction》,也…

c++基础知识补充4

单独使用词汇 using std::cout; 隐式类型转换型初始化:如A a1,,此时可以形象地理解为int i1;double ji;,此时1可以认为创建了一个值为1的临时对象,然后对目标对象进行赋值,当对象为多参数时,使用(1&#xf…

2024最新算法:电鳗觅食优化算法(Electric eel foraging optimization,EEFO)求解23个基准函数(提供MATLAB代码)

一、电鳗觅食优化算法 电鳗觅食优化算法(Electric eel foraging optimization,EEFO)由Weiguo Zhao等人提出的一种元启发算法,EEFO从自然界中电鳗表现出的智能群体觅食行为中汲取灵感。该算法对四种关键的觅食行为进行数学建模:相…

2000-2021年各省互联网普及率数据

2000-2021年各省互联网普及率数据 1、时间:2000-2021年 2、指标:省级:行政区划代码、地区、年份、互联网普及率(%) 3、来源:互联网络信息中心;各地统计局 4、指标解释:指互联网用户数占常住人口总数的比…

环形链表详解(让你彻底理解环形链表)

文章目录 一.什么是环形链表?二.环形链表的例题(力扣) 三.环形链表的延伸问题 补充 一.什么是环形链表? 环形链表是一种特殊类型的链表数据结构,其最后一个节点的"下一个"指针指向链表中的某个节点&#xff…

【tableau学习笔记】tableau无法连接数据源

【tableau学习笔记】tableau无法连接数据源 背景: 学校讲到Tableau,兴奋下载Kaggle Excel,一看后缀CSV,导入Tableau发现报错“tableau无法连接数据源”,自作聪明改为后缀XLSX,bug依旧。 省流&#xff1a…

QML中动态表格修改数据

1.qml文件中的实现代码 import QtQuick 2.15 import QtQuick.Window 2.15import QtQuick.Controls 2.0 import Qt.labs.qmlmodels 1.0 import QtQuick.Layouts 1.15Window {width: 640height: 480visible: truetitle: qsTr("Hello World")TableModel{id:table_model…

【风格迁移】URST:解决超高分辨率图像的风格迁移问题

URST:解决超高分辨率图像的风格迁移问题 提出背景URST框架的整体架构 提出背景 论文:https://arxiv.org/pdf/2103.11784.pdf 代码:https://github.com/czczup/URST?v1 有一张高分辨率的风景照片,分辨率为1000010000像素&#…

【C++ AVL树】

文章目录 AVL树AVL树的概念AVL树节点的定义AVL树的插入AVL树的旋转右单旋左单旋左右双旋右左双旋 代码实现 总结 AVL树 AVL树的概念 二叉搜索树在顺序有序或接近有序的情况下,而插入搜索树将退化为单叉树,此时查找的时间复杂度为O(n),效率低…

Java通过jedis连接redis一些常用方法

小伙伴们好,欢迎关注,一起学习,无线进步 以下内容为学习redis过程中的一些笔记 文章目录 Jedis常用API判断keyStringListSetHashZset事务 Jedis 使用 Java 来操作 Redis,知其然并知其所以然 什么是Jedis 是 Redis 官方推荐的 jav…

#WEB前端(DIV、SPAN)

1.实验&#xff1a;DIV、SPAN 2.IDE&#xff1a;VSCODE 3.记录&#xff1a; 类? 4.代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdev…

【java、微服务、spring】SpringCloud

服务拆分 1. 不同微服务&#xff0c;不要重复开发相同业务 2&#xff0e;微服务数据独立&#xff0c;不要访问其它微服务的数据库 3&#xff0e;微服务可以将自己的业务暴露为接口&#xff0c;供其它微服务调用 远程调用 提供者与消费者 服务提供者&#xff1a;一次业务中…

扼杀网络中的环路:STP、RSTP、MSTP

目录 前言&#xff1a; 一、STP&#xff08;Spanning Tree Protocol&#xff09; 1.1 STP功能 1.2 STP应用 二、RSTP&#xff08;Rapid Spanning Tree Protocol&#xff09; 2.1 RSTP功能 2.2 RSTP应用 三、MSTP&#xff08;Multiple Spanning Tree Protocol&#xff0…

ScanDomainEuorg:批量查询 eu.org 域名注册情况(附带源码)

引言 eu.org 很长时间都没有审批了&#xff0c;但是我觉得只是时间长短问题&#xff0c;早晚会再次审批的。 既然如此&#xff0c;大可以未雨绸缪一般&#xff0c;趁着大家对其“失望”的时间段&#xff0c;看看有哪些好看的前缀没有被注册。 原理 灵感来源于 域名 .eu.org…

Java 网络面试题解析

1. Http 协议的状态码有哪些&#xff1f;含义是什么&#xff1f;【重点】 200&#xff1a;OK&#xff0c;客户端请求成功。 301&#xff1a;Moved Permanently&#xff08;永久移除&#xff09;&#xff0c;请求的URL已移走。Response中应该包含一个Location URL&#xff0c;…

Thinkphp框架漏洞--->5.0.23 RCE

1.Thinkphp ThinkPHP是一个免费开源的&#xff0c;快速、简单的面向对象的轻量级PHP开发框架&#xff0c;是为了敏捷WEB应用开发和简化 企业应用开发而诞生的。 2.漏洞原理及成因 该漏洞出现的原因在于 ThinkPHP5框架底层对控制器名过滤不严 &#xff0c;从而让攻击者可以通过…

QoS简单配置案例

1、两边两个方向做相同的配置&#xff1a;入口复杂流分类用mqc方式配置&#xff0c;ds内设备入口配简单流分类。 2、两边两个方法做拥塞管理配置&#xff0c;拥塞管理配置思路&#xff1a; 拥塞管理的两种配置方法&#xff08;全部用一种也可以&#xff0c;这里学习就用了两种…

Vue3 条件渲染 v-if

v-if 指令&#xff1a;用于控制元素的显示或隐藏。 执行条件&#xff1a;当条件为 false 时&#xff0c;会将元素从 DOM 中删除。 应用场景&#xff1a;适用于显示隐藏切换频率较低的场景。 语法格式&#xff1a; <div v-if"数据">内容</div> 基础用…

解决 MySQL 未运行但锁文件存在的问题

查看mysql状态时&#xff0c;显示错误信息"ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql) exists"。 解决步骤 1、检查 MySQL 进程是否正在运行 在继续之前&#xff0c;我们首先需要确定 MySQL 进程是否正在运行。我们可以使用以下命令检查…