2022-09-29质量保障00

Istanbul 测试覆盖率的实现原理

Istanbul (伊斯坦布尔)是一个基于 JavaScript 的测试覆盖率统计工具,目前绝大多数测试框架比如 jest mocha 等都是使用 Istanbul 来统计覆盖率的。

测试覆盖率的四个维度

  • Statements
    • 语句覆盖率,所有语句的执行率;
  • Branches
    • 分支覆盖率,所有代码分支如 if、三目运算的执行率;
  • Functions
    • 函数覆盖率,所有函数的被调用率;
  • Lines
    • 行覆盖率,所有有效代码行的执行率,和语句类似,但是计算方式略有差别;

Istanbul 的使用

istanbul 最新的版本为: nyc,官方站点为:https://istanbul.js.org,github: https://github.com/istanbuljs/nyc。下面将简称 Istanbul 为 nyc

传统的前端项目测试,假设使用 mocha 测试,我们会执行以下的测试用例:

`mocha test/suite/\*_/_.spec.js`

接着开发者安装 nyc npm 类库(npm install nyc -D),然后加个 nyc 前缀就会自动 完成运行时的覆盖统计与最终结果展现;

// nyc 无参数的默认用法
nyc mocha test/suite/**/\*.spec.js
// nyc 携带参数:html 格式
nyc --reporter=html mocha test/suite/**/\*.spec.js
// 也可以通过项目根目录增加配置文件(如:nyc.config.js)的形式,然后执行上面的命令
module.exports = {
reporter: ['html']
}

该命令执行时,会依次完成以下几件事:

  1. 将项目 src 源码目录中的 JS 文件做转换并缓存起来;

  2. 接着将后面的 mocha 参数放到子进程(child_process)执行,即:调用 mocha 执行测试用例;

  3. 测试用例中所测试的 src 源码文件实际是上面的缓存文件,期间完成的语句与分支执行的统计,记录在 JS 内存的某个变量中;

  4. 子进程的测试用例执行结束之后,将统计数据发送给 nyc 命令所在线程并保存到文件,默认目录名为:.nyc_output,它记录了本次测试的代码覆盖最完整的数据;

  5. nyc 线程内部调用 report 方法,完成从原始数据到可读性良好的内容转换;它会将 .nyc_output 目录中的数据读取出来,并使用 html 格式 进行转换,并默认生成在目录 coverage 下;

2022-09-29质量保障00

cypress 笔记

cypress 是通过模拟用户点击来测试的端到端测试框架,它也允许你编写集成测试与单元测试。

cypress - 中文文档

Cypress 为什么好?

  • 真实模拟用户点点点,可靠高效
    • 免去开发完成后大量手动去检查的行为,即原本代价很高的 UI 测试。
  • 易发现因修改而造成的其他模块 BUG
    • 开发人员开发某个功能,对自己模块的需求多数情况都是完成的不错的,但有时候因为改 A 模块而导致但 B 模块的 BUG 难以用单测发现
  • 整个流程拉通,甚至能及时发现后端 BUG
    • 调用真实后端接口,如果原本正常然后突然跑不通,就是后端问题
  • 查错方便
    • Cypress 支持录制视频与截图,跑挂了有截图还有当时的报错信息
  • 最低成本保证主流程
    • Cypress 属于黑盒测试,Cypress 模拟用户从头到尾使用网站的流程。能最简单又快速的避免那种页面都挂了但还不知道的情况,也是最惨情况。

经验

隔离环境测试

Cypress 是用的真正的后端数据,而不是 mock 一个数据然后测试组件行为。所以在测试时最好不要使用线上环境,这会使得后端写入很多测试脏数据。最好的就是在专门的沙箱环境测试,如果有租户概念可用新租户,测试时机为发起 MR 代码时。

Cypress 不适合边界测试、细节测试

Cypress 主要用于跑通主流程,测试的是预期内的东西,而对于有大量计算或复杂判断的纯函数方法而言,单测肯定是更好。

2022-09-28笔试题00

题目

Given a compressed string, return its original form.

For example.

uncompress('3(ab)') // 'ababab'
uncompress('3(ab2(c))') // 'abccabccabcc'

a number k followed by a pair of parenthesis, meaning to repeat the substring inside the parenthesis by k times, k is positive integer. inputs are guaranteed to be valid input like above example, there is no numerical digit in original form.

2022-09-28业务场景00

package.json

npm 离不开 package.json ,要了解 npm 的运行机制,我们先看看 package.json 文件是做什么的。首先 package.json 文件是每个前端项目存在于根目录的文件,包含了项目的一些基本信息(例如项目名称,版本号,描述,一些脚本,依赖等等),大致的结构如下:

{
  "name": "whyknown",
  "version": "1.0.0",
  "description": "whyknown,前端开发者必备网站",
  "main": "src/index.js",
  "scripts": {
    "start": "node index.js",
    "lint": "eslint **/*.js"
  },
  "dependencies": {
    "express": "^4.16.4",
    "compression": "~1.7.4"
  },
  "devDependencies": {
    "eslint": "^5.16.0",
    "nodemon": "^1.18.11"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/xxx.git"
  },
  "author": "whyknown",
  "contributors": [
    {
      "name": "whyknown",
      "email": "example@example.com",
      "url": "https://www.whyknown.com"
    }
  ],
  "keywords": ["server", "osiolabs", "express", "compression"]
}

我们这里重点关注 script 的配置,该配置罗列了一些可以运行的脚本,当我们在根目录执行 npm run 或者 yarn run 的时候,就会去调用这里的命令。我们拿上面的 start 命令来讲解。

2022-09-28JavaScript00

compose

compose 是函数式编程中一个非常重要的函数,compose 的函数作用就是组合函数的,将函数串联起来执行。将多个函数组合起来,一个函数的输出结果是另一个函数的输入参数,一旦第一个函数开始执行,就会像多米诺骨牌一样推导执行了。

2.1 简单例子

比如有这样的需求,输入一个名字 yideng,然后全部变成大写,打印输出 HELLO YIDENG,我们可以考虑用函数组合的方法来解决这个问题,需要两个函数 greeting、toUpper

const greeting = (name) => `hello ${name}`;
const toUpper = (str) => str.toUpperCase();
const fn = compose(toUpper, greeting);
console.log(fn("yideng"));
// HELLO YIDENG

这就是 compose 的大致使用,主要有以下几点:

  • compose 参数是函数,返回也是一个函数
  • 除了第一个函数接受参数,其它函数接受的都是上一个函数的返回值,所以初始函数的参数是多元的,而其它函数的接受值是一元的。
  • compose 函数可以接受任意的参数,所有的参数都是函数,且执行方向是自右向左的,初始函数一定放到参数的最右面。