Jest 测试使用说明

Jest 测试

什么是测试

作为开发来讲可以简单把代码分为两种,一种是业务代码,一种是业务无关的代码。测试代码就是典型的业务无关的代码。不过按照我的定义可以把测试代码定位为:可以保证业务代码是否能够按照预期运行的代码。有些人会把这个叫做 TDD,但是TDD(Test-Driven Development or Test-Driven Design)只是开发的一种思路或者说是习惯,先写测试用例,然后实现业务逻辑。

坦白讲,作为实用主义的程序员,先写测试用例还是后写测试用例或是不写测试,只要线上代码运行没问题就行了,测试不测试没那么重要。但是如果是写一个第三方库,业务中台代码,项目核心代码模块。此时的测试代码就十分有必要,如果你做开源如果没有 test 文件夹,可能你的方案就基本没人使用。

为什么做测试

为什么做测试

自动化测试就是面向这些问题而生的。

测试分类

测试分类

单元测试

单元测试是最基础的自动化测试,用来检测项目当中的最小可测单元,例如工具函数、基础组件等

集成测试

在单元测试的基础上,不同功能集成在一起,验证整体功能

E2E测试

相对真实、完整链路的模拟真实操作验证

压力测试

压测的目的是在于找到系统的瓶颈,一定是要确定系统某个方面达到瓶颈了。对于web应用,系统的瓶颈往往会是数据库;系统满负荷运作的时候,数据库的CPU或者是磁盘IO。

ui测试

对ui设计效果的验证,对数据渲染、交互上的验证

测试工具

  • 单元测试(Unit Test)有 Jest, Mocha
  • UI测试Test Render, Enzyme,
  • 端到端(E2E Test)Cypress.io、Nightwatch.js、Puppeteer、TestCafe

Jest基本使用

1. 安装依赖

# jest 开发依赖npm install --save-dev jest# babel 扩展包npm install --save-dev babel-jest @babel/core @babel/preset-env# Ts测试依赖npm install --save-dev @babel/preset-typescript# jest库 Ts 预处理器npm install --save-dev ts-jest#  jest类型定义Typesnpm install --save-dev @types/jest#  另外一个类型定义模块npm install --save-dev @jest/globals

2. 开发支持

我们先写一个两数相加的函数。 首先,创建 src/caculate.js 文件︰

const add = (a, b) => a + bconst remove = (a, b) => a - bconst multiply = (a, b) => a * bconst divide = (a, b) => a / b

module.exports = {  add, divide, multiply, remove,}

然后,创建名为 test/sum.test.js 的文件。 此文件中将包含我们的实际测试︰

const { add, divide, multiply, remove } = require('../src/caculate')

describe('calculate module', () => {  test('add', () => {    expect(add(1, 2)).toBe(3)  })

  test('remove', () => {    expect(remove(1, 2)).toBe(-1)  })

  test('multiply', () => {    expect(multiply(1, 2)).toBe(2)  })

  test('divide', () => {    expect(divide(1, 2)).toBe(0.5)  })})

最后,运行 npx testnpm run test ,Jest将打印下面这个消息:

 PASS  test/caculate.test.js

3. 指定配置文件

基于您的项目,Jest将向您提出几个问题,并将创建一个基本的配置文件,每个选项都有一个简短的说明:

jest --init

最后会自动生成这样的配置文件,常用的带有中文说明

module.exports = {  // All imported modules in your tests should be mocked automatically  // 类型:boolean,默认:false,在每次测试前自动清除模拟的上下文  // automock: false,

  // Stop running tests after `n` failures  // 失败多少次后停止测试  // bail: 0,

  // The directory where Jest should store its cached dependency information  // 指定测试缓存文件夹  // cacheDirectory: "C:\\Users\\U\\AppData\\Local\\Temp\\jest",

  // Automatically clear mock calls, instances, contexts and results before every test  // 在每一个测试之前自动清除模拟类、实例、上下文和结果  clearMocks: true,

  // Indicates whether the coverage information should be collected while executing the test  // 类型:boolean,默认:false,是否开启 覆盖率  collectCoverage: true,

  // An array of glob patterns indicating a set of files for which coverage information should be collected  // collectCoverageFrom: undefined,

  // The directory where Jest should output its coverage files  // 生成的覆盖率文件的文件位置  coverageDirectory: "coverage",

  // An array of regexp pattern strings used to skip coverage collection  // 需要排除覆盖率文件夹  // coveragePathIgnorePatterns: [  //   "\\\\node_modules\\\\"  // ],

  // Indicates which provider should be used to instrument code for coverage  // 覆盖率测试需要的插件  // coverageProvider: "babel",

  // A path to a module which exports an async function that is triggered once before all test suites  // globalSetup: undefined,

  // A path to a module which exports an async function that is triggered once after all test suites  // globalTeardown: undefined,

  // A set of global variables that need to be available in all test environments  // globals: {},

  // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.  // 最大测试Workers数   // maxWorkers: "50%",

  // An array of directory names to be searched recursively up from the requiring module's location  // moduleDirectories: [  //   "node_modules"  // ],

  // An array of file extensions your modules use  moduleFileExtensions: [    "js",    // "mjs",    // "cjs",    // "jsx",    "ts",    // "tsx",    // "json",    // "node"  ],

  // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module  // moduleNameMapper: {},

  // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader  // modulePathIgnorePatterns: [],

  // Activates notifications for test results  // notify: false,

  // An enum that specifies notification mode. Requires { notify: true }  // notifyMode: "failure-change",

  // A preset that is used as a base for Jest's configuration  // preset: undefined,

  // Run tests from one or more projects  // projects: undefined,

  // Use this configuration option to add custom reporters to Jest  // reporters: undefined,

  // Automatically reset mock state before every test  // resetMocks: false,

  // Reset the module registry before running each individual test  // resetModules: false,

  // A path to a custom resolver  // resolver: undefined,

  // Automatically restore mock state and implementation before every test  // restoreMocks: false,

  // The root directory that Jest should scan for tests and modules within  // rootDir: undefined,

  // A list of paths to directories that Jest should use to search for files in  // roots: [  //   "<rootDir>"  // ],

  // Allows you to use a custom runner instead of Jest's default test runner  // runner: "jest-runner",

  // The paths to modules that run some code to configure or set up the testing environment before each test  // setupFiles: [],

  // A list of paths to modules that run some code to configure or set up the testing framework before each test  // setupFilesAfterEnv: [],

  // The number of seconds after which a test is considered as slow and reported as such in the results.  // slowTestThreshold: 5,

  // A list of paths to snapshot serializer modules Jest should use for snapshot testing  // snapshotSerializers: [],

  // The test environment that will be used for testing  // 用于模拟测试的测试环境,如果我们用到浏览器的环境(如:document),可以用 jsdom代替  // testEnvironment: "jest-environment-node",

  // Options that will be passed to the testEnvironment  // 测试环境变量  // testEnvironmentOptions: {},

  // Adds a location field to test results  // testLocationInResults: false,

  // The glob patterns Jest uses to detect test files  // 测试匹配规则  testMatch: [    "**/__tests__/**/*.[jt]s?(x)",    "**/?(*.)+(spec|test).[tj]s?(x)"  ],

  // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped  testPathIgnorePatterns: [    "\\\\node_modules\\\\"  ],

  // The regexp pattern or array of patterns that Jest uses to detect test files  // testRegex: [],

  // This option allows the use of a custom results processor  // testResultsProcessor: undefined,

  // This option allows use of a custom test runner  // testRunner: "jest-circus/runner",

  // A map from regular expressions to paths to transformers  // transform: undefined,

  // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation  // transformIgnorePatterns: [  //   "\\\\node_modules\\\\",  //   "\\.pnp\\.[^\\\\]+$"  // ],

  // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them  // unmockedModulePathPatterns: undefined,

  // Indicates whether each individual test should be reported during the run  // verbose: undefined,

  // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode  // watchPathIgnorePatterns: [],

  // Whether to use watchman for file crawling  // watchman: true,}

Jest 匹配器

1. 常用匹配器

基本上函数名可以见名知意。

// 精确匹配test('two plus two is four', () => {  expect(2 + 2).toBe(4);});test('null', () => {  const n = null;  expect(n).toBeNull();  expect(n).toBeDefined();  expect(n).not.toBeUndefined();  expect(n).not.toBeTruthy();  expect(n).toBeFalsy();});

// 空值匹配test('zero', () => {  const z = 0;  expect(z).not.toBeNull();  expect(z).toBeDefined();  expect(z).not.toBeUndefined();  expect(z).not.toBeTruthy();  expect(z).toBeFalsy();});

// 数值匹配test('two plus two', () => {  const value = 2 + 2;  expect(value).toBeGreaterThan(3);  expect(value).toBeGreaterThanOrEqual(3.5);  expect(value).toBeLessThan(5);  expect(value).toBeLessThanOrEqual(4.5);

  // toBe and toEqual are equivalent for numbers  expect(value).toBe(4);  expect(value).toEqual(4);});

// 字符串匹配test('there is no I in team', () => {  expect('team').not.toMatch(/I/);});

test('but there is a "stop" in Christoph', () => {  expect('Christoph').toMatch(/stop/);});

// 数组和可迭代对象const shoppingList = [  'diapers',  'kleenex',  'trash bags',  'paper towels',  'milk',];

test('shoppingList数组中包含milk', () => {  expect(shoppingList).toContain('milk');  expect(new Set(shoppingList)).toContain('milk');});

// Exception 匹配function compileAndroidCode() {  throw new Error('you are using the wrong JDK!');}

test('compiling android goes as expected', () => {  expect(() => compileAndroidCode()).toThrow();  expect(() => compileAndroidCode()).toThrow(Error);

  // You can also use a string that must be contained in the error message or a regexp  expect(() => compileAndroidCode()).toThrow('you are using the wrong JDK');  expect(() => compileAndroidCode()).toThrow(/JDK/);

  // Or you can match an exact error mesage using a regexp like below  expect(() => compileAndroidCode()).toThrow(/^you are using the wrong JDK$/); // Test fails  expect(() => compileAndroidCode()).toThrow(/^you are using the wrong JDK!$/); // Test pass});

2. 异步代码匹配

为你的测试返回一个Promise,则Jest会等待Promise的resove状态 如果 Promise 的状态变为 rejected, 测试将会失败。

test('the data is peanut butter', () => {  return fetchData().then(data => {    expect(data).toBe('peanut butter');  });});

// Async/Await 匹配test('the data is peanut butter', async () => {  const data = await fetchData();  expect(data).toBe('peanut butter');});

test('the fetch fails with an error', async () => {  expect.assertions(1);  try {    await fetchData();  } catch (e) {    expect(e).toMatch('error');  }});

test('the data is peanut butter', async () => {  await expect(fetchData()).resolves.toBe('peanut butter');});

test('the fetch fails with an error', async () => {  await expect(fetchData()).rejects.toMatch('error');});

Jest中级使用

全局函数

我们通过 sum.test.js文件,发现了 describeexpect,但我们并没有引入对应的函数,却能正常的使用,这是为什么呢?

实际上 Jest会将这些方法和对象注入到测试文件的 全局环境里,所以我们在使用的时候并不需要通过 importrequire

当然,如果你一定要引用,可以这样引用:

import {describe, expect, test} from '@jest/globals

describe

describe: 描述块,将一组功能相关的测试用例组合在一块

it

it: 别名 test, 用来存放测试用例,每一个it就是一个测试用例

钩子函数

写测试的时候你经常需要在运行测试前做一些准备工作,和在运行测试后进行一些整理工作。 Jest 提供辅助函数来处理这个问题。

afterAll 和 beforeAll

afterAll: 所有的测试用例执行完 执行的方法,如果传入的回调函数返回值是 promise 或者 generatorJest 会等待 promise resolve 再继续执行。

beforeAll: 与 afterAll相反, 所有的测试用例执行之 执行的方法

afterEach 和 beforeEach

afterEach: 也 afterAll相比, afterEach可以在每个测试完成 都运行一遍

beforeEachbeforeEach可以在每个测试完成之 都运行一遍

// global.js

export const global = function(msg) {  console.log(msg)}

// global.test.jsimport { add } from '../src/caculate'import { global } from '../src/global'

beforeAll(() => {  console.log('beforeAll')})

afterAll(() => {  console.log('afterAll')})

describe('calculate module', () => {

  test('global start', () => {    expect(1).toBe(1)    global('global start')  })

  test('global end', () => {    expect(1).toBe(1)    global('global end')  })

})

运行结果

运行结果

加上 beforeEachafterEach

import { global } from '../src/global'

beforeAll(() => {  console.log('beforeAll')})

afterAll(() => {  console.log('afterAll')})

beforeEach(() => {  console.log('beforeEach')})

afterEach(() => {  console.log('afterEach')})

describe('calculate module', () => {

  test('global start', () => {    expect(1).toBe(1)    global('global start')  })

  test('global end', () => {    expect(1).toBe(1)    global('global end')  })

})

运行结果,可以看到每一个 test 之前都运行了beforeEach 运行之后立马云 afterEach

运行结果

Jest高级使用

模拟函数

Mock 函数允许你测试代码之间的连接——实现方式包括:擦除函数的实际实现、捕获对函数的调用 ( 以及在这些调用中传递的参数) 、在使用 new 实例化时捕获构造函数的实例、允许测试时配置返回值。

有两种方法可以模拟函数:要么在测试代码中创建一个 mock 函数,要么编写一个手动 mock来覆盖模块依赖。

假设我们要测试函数 forEach 的内部实现,这个函数为传入的数组中的每个元素调用一次回调函数。

function forEach(items, callback) {  for (let index = 0; index < items.length; index++) {    callback(items[index]);  }}

为了测试此函数,我们可以使用一个 mock 函数,然后检查 mock 函数的状态来确保回调函数如期调用。

const mockCallback = jest.fn(x => 42 + x);forEach([0, 1], mockCallback);

// 此 mock 函数被调用了两次expect(mockCallback.mock.calls.length).toBe(2);

// 第一次调用函数时的第一个参数是 0expect(mockCallback.mock.calls[0][0]).toBe(0);

// 第二次调用函数时的第一个参数是 1expect(mockCallback.mock.calls[1][0]).toBe(1);

// 第一次函数调用的返回值是 42expect(mockCallback.mock.results[0].value).toBe(42);

覆盖率报告

// jest.config.js  collectCoverage: true,coverageDirectory: "coverage",

jest.config.js 中添加如下两个选项。运行测试

运行结果
  • %stmts:是 语句覆盖率(statement coverage),是不是每个语句都执行了
  • %Branch:是 分支覆盖率(branch coverage),是不是每个if代码块都执行了
  • %Funcs:是 函数覆盖率(functioncoverage,是不是每个函数都调用了
  • %Lines:是 行覆盖率(line coverage,是不是每一行都执行了

查看 coverage 文件夹

coverage`

打开index.html 查看结果

coverage

最后可以使用Circle等集成工具自动化测试

项目代码地址

https://github.com/web0matrix/Web0matrix/tree/main/jest 欢迎点赞。模拟函数部分使用较少,还有待补充。

参考

  • https://mp.weixin.qq.com/s/2mcazw7-nL-0j1-0qkvsKQ
  • https://jestjs.io/zh-Hans/docs/setup-teardown

本文由 mdnice 多平台发布

Jest测试入门到使用相关推荐

  1. 使用Jest测试JavaScript (入门篇)

    1 什么是 Jest? Jest是 Facebook 的一套开源的 JavaScript 测试框架, 它自动集成了断言.JSDom.覆盖率报告等开发者所需要的所有测试工具,是一款几乎零配置的测试框架. ...

  2. 使用Jest测试JavaScript (入门篇) 1

    1 什么是 Jest? Jest Jest是 Facebook 的一套开源的 JavaScript 测试框架, 它自动集成了断言.JSDom.覆盖率报告等开发者所需要的所有测试工具,是一款几乎零配置的 ...

  3. Puppeteer E2E测试入门

    Puppeteer E2E测试入门 本文内容涉及ES6 async.jest的相关知识,对于以上内容不太了解的读者可以先了解相关内容. Puppeteer是什么 它由Chrome官方团队提供,通过De ...

  4. Jest测试框架学习(一)

    前言 jest是针对JavaScript的测试框架.如果遵循TDD原则,在任何功能开发之前都需要先写测试.而测试分为单元测试,集成测试和系统测试. 单元测试 单元测试可以理解为对于单个函数(单一功能) ...

  5. Android渗透测试Android渗透测试入门教程大学霸

    Android渗透测试Android渗透测试入门教程大学霸 第1章  Android渗透测试 Android是一种基于Linux的自由及开放源代码的操作系统,主要用于移动设备,如智能手机.平板等.目前 ...

  6. jest测试ajax,ajax – 如何使用Jest来测试React呈现的异步数据?

    我正在使用React for render和Jest / Jasmine进行测试.我使用旧的Jest / Jasmine等待测试并运行,但现在这些已经在Jasmine 2中消失了,我不知道如何用新的a ...

  7. react jest测试_如何使用React测试库和Jest开始测试React应用

    react jest测试 Testing is often seen as a tedious process. It's extra code you have to write, and in s ...

  8. react jest测试_如何使用Jest和react-testing-library测试Socket.io-client应用程序

    react jest测试 by Justice Mba 由Mba法官 如何使用Jest和react-testing-library测试Socket.io-client应用程序 (How to test ...

  9. react jest测试_如何设置Jest和Enzyme来测试React Native应用

    react jest测试 by Sam Ollason 通过萨姆·奥拉森(Sam Ollason) This short article shares my experiences setting u ...

最新文章

  1. 广东计算机一级考试可以用计算器吗,你考试用不用计算器?
  2. 小胖机器人能刷碗吗_小胖机器人好不好?透过真相看本质
  3. python如何判断是否有弹出框_Selenium2+python自动化47-判断弹出框存在(alert_is_present)【转载】...
  4. SpringBoot2.0 Actuator 监控参数说明
  5. [签名算法]DSA 算法
  6. 2048游戏c语言linux简易代码,C语言实现2048游戏代码
  7. iview table数据直接导出_使用iview的exportcsv怎样导出嵌套数据
  8. 这几个公众号带你看看BAT的工作情况
  9. 《Java与模式》笔记(一)
  10. PostgreSQL 优势,MySQL 数据库自身的特性并不十分丰富,触发器和存储过程的支持较弱,Greenplum、AWS 的 Redshift 等都是基于 PostgreSQL 开发的...
  11. 新硬盘显示有储存空间但无法分区_容量更足高速无忧,奥睿科迅龙V500 NVME硬盘体验...
  12. 数学算法对计算机编程的优化
  13. cad图形不见了怎么办_CAD软件常见问题解答,CAD中的工具栏不见了怎么办?如何清理图形...
  14. Unity Remote5 使用
  15. 基于云服务创建实时运营数据分析服务(二)
  16. 苹果手机iCloud备忘录删除怎么恢复
  17. Python切片工具 pillow
  18. 生而为人,我很抱歉!深夜爬虫, 我很抱歉 ,附微信 “ 网抑云” 公众号爬虫教程!
  19. jsp+servlet实现个人博客系统
  20. 计算机毕业设计ssm陈氏商城9pd36系统+程序+源码+lw+远程部署

热门文章

  1. intellij idea 激活码 activate code 绝对有效,简单易操作
  2. r5处理器_【玩码】RedmiBook 三款齐发,标配最新锐龙 4000 系列处理器
  3. Element属性和方法
  4. ODBC读写创建excel表格
  5. 如何在插上网线与连接到WiFi的同时,使用WiFi网络?
  6. 深入理解Java虚拟机(第三版)-- 判定对象存活算法、引用、回收方法区
  7. 谷歌浏览器切换黑色背景
  8. 走近垒球运动·体育项目
  9. 少女前线一直提示服务器维护,少女前线进不去黑屏怎么办 闪退解决方法
  10. 计算机网络 洪泛算法,泛洪