【实战】二、Jest难点进阶(三) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(七)

这篇具有很好参考价值的文章主要介绍了【实战】二、Jest难点进阶(三) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(七)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


学习内容来源:Jest入门到TDD/BDD双实战_前端要学的测试课


相对原教程,我在学习开始时(2023.08)采用的是当前最新版本:

版本
@babel/core ^7.16.0
@pmmmwh/react-refresh-webpack-plugin ^0.5.3
@svgr/webpack ^5.5.0
@testing-library/jest-dom ^5.17.0
@testing-library/react ^13.4.0
@testing-library/user-event ^13.5.0
babel-jest ^27.4.2
babel-loader ^8.2.3
babel-plugin-named-asset-import ^0.3.8
babel-preset-react-app ^10.0.1
bfj ^7.0.2
browserslist ^4.18.1
camelcase ^6.2.1
case-sensitive-paths-webpack-plugin ^2.4.0
css-loader ^6.5.1
css-minimizer-webpack-plugin ^3.2.0
dotenv ^10.0.0
dotenv-expand ^5.1.0
eslint ^8.3.0
eslint-config-react-app ^7.0.1
eslint-webpack-plugin ^3.1.1
file-loader ^6.2.0
fs-extra ^10.0.0
html-webpack-plugin ^5.5.0
identity-obj-proxy ^3.0.0
jest ^27.4.3
jest-enzyme ^7.1.2
jest-resolve ^27.4.2
jest-watch-typeahead ^1.0.0
mini-css-extract-plugin ^2.4.5
postcss ^8.4.4
postcss-flexbugs-fixes ^5.0.2
postcss-loader ^6.2.1
postcss-normalize ^10.0.1
postcss-preset-env ^7.0.1
prompts ^2.4.2
react ^18.2.0
react-app-polyfill ^3.0.0
react-dev-utils ^12.0.1
react-dom ^18.2.0
react-refresh ^0.11.0
resolve ^1.20.0
resolve-url-loader ^4.0.0
sass-loader ^12.3.0
semver ^7.3.5
source-map-loader ^3.0.0
style-loader ^3.3.1
tailwindcss ^3.0.2
terser-webpack-plugin ^5.2.5
web-vitals ^2.1.4
webpack ^5.64.4
webpack-dev-server ^4.6.0
webpack-manifest-plugin ^4.0.2
workbox-webpack-plugin ^6.4.1"

具体配置、操作和内容会有差异,“坑”也会有所不同。。。


一、Jest 前端自动化测试框架基础入门

  • 一、Jest 前端自动化测试框架基础入门(一)

  • 一、Jest 前端自动化测试框架基础入门(二)

  • 一、Jest 前端自动化测试框架基础入门(三)

  • 一、Jest 前端自动化测试框架基础入门(四)

二、Jest难点进阶

  • 二、Jest难点进阶(一)
  • 二、Jest难点进阶(二)

3.mock timers

接下来学习一下对定时器的模拟

新建 Jest\src\lesson11\index.js

export default (cbk) => {
  setTimeout(() => {
    cbk()
  }, 3000)
}

新建 Jest\src\lesson11_tests_\index.test.js

import timer from "../index";

test('测试 timer', () => {
  timer(() => {
    expect(2).toEqual(1)
  })
})

执行测试用例,竟然成功了。。由于timer是一个异步函数,jest不会等cbk函数执行完毕,在cbk挂起期间没有明显问题直接就会返回成功

给它加点料,编辑 Jest\src\lesson11_tests_\index.test.js

import timer from "../index";

test('测试 timer', (done) => {
  timer(() => {
    expect(2).toEqual(1)
    done()
  })
})

执行测试用例报错,这才对嘛(改为 expect(2).toEqual(1) 后会成功)

使用了done(),这时候测试用例就会等done()执行完毕出结果,但是若时间设置较长,这样的等待显然是不合理的

接下来进入正题,模拟 timer

编辑 Jest\src\lesson11_tests_\index.test.js(模拟 timer 后换一种测试方式)

import timer from "../index";

jest.useFakeTimers()

test('测试 timer', () => {
  const fn = jest.fn();
  timer(fn);
  expect(fn).toHaveBeenCalledTimes(1)
})

使用 jest.useFakeTimers() 模拟 timer

执行测试用例报错,信息如下(确实模拟了timer,但是没有执行)

Expected number of calls: 1
Received number of calls: 0

编辑 Jest\src\lesson11_tests_\index.test.js(执行模拟的 timer

import timer from "../index";

jest.useFakeTimers()

test('测试 timer', () => {
  const fn = jest.fn();
  timer(fn);
  jest.runAllTimers()
  expect(fn).toHaveBeenCalledTimes(1)
})

执行测试用例成功!

接下来看看其他相关用法

编辑 Jest\src\lesson11\index.js(定时器里面再放入一层,并执行 cbk 函数)

export default (cbk) => {
  setTimeout(() => {
    cbk()
    setTimeout(() => {
      cbk()
    }, 3000)
  }, 3000)
}

这时再运行之前的测试用例就通不过了,因为 runAllTimers 后,cbk 执行了两次

如何测试时只运行当前已触发的定时器呢?(运行代码时,只有最外层定时器加入队列,即触发)

编辑 Jest\src\lesson11_tests_\index.test.js(runAllTimers 改为 runOnlyPendingTimers

import timer from "../index";

jest.useFakeTimers()

test('测试 timer', () => {
  const fn = jest.fn();
  timer(fn);
  jest.runOnlyPendingTimers()
  expect(fn).toHaveBeenCalledTimes(1)
})

执行测试用例成功!

很显然只有这两个在日常测试是不够用的,接下来尝试另一个函数

编辑 Jest\src\lesson11_tests_\index.test.js(runOnlyPendingTimers 改为 advanceTimersByTime

import timer from "../index";

jest.useFakeTimers()

test('测试 timer', () => {
  const fn = jest.fn();
  timer(fn);
  jest.advanceTimersByTime(3000)
  expect(fn).toHaveBeenCalledTimes(1)
})

执行测试用例成功!

advanceTimersByTime 相当于是时间快进器,测试用例中在 3000 这个节点 fn 执行第一次,在 6000 这个节点 fn 执行第二次,因此在另外几个时间段的执行结果便呼之欲出了

当然 advanceTimersByTime 可以使用多次,不过需要注意的是,下一次使用是在上一次”快进“的基础上再次”快进“的

编辑 Jest\src\lesson11_tests_\index.test.js(多次使用advanceTimersByTime

import timer from "../index";

jest.useFakeTimers()

test('测试 timer', () => {
  const fn = jest.fn();
  timer(fn);
  jest.advanceTimersByTime(3000)
  expect(fn).toHaveBeenCalledTimes(1)
  jest.advanceTimersByTime(3000)
  expect(fn).toHaveBeenCalledTimes(2)
})

执行测试用例成功!

但是多个测试用例之间 advanceTimersByTime 会有相互影响

编辑 Jest\src\lesson11\index.js(在之前定时器里面再放入一层的基础上,再放入一层,并再执行 cbk 函数,一共三层,最终执行三次)

export default (cbk) => {
  setTimeout(() => {
    cbk()
    setTimeout(() => {
      cbk()
      setTimeout(() => {
        cbk()
      }, 3000)
    }, 3000)
  }, 3000)
}

编辑 Jest\src\lesson11_tests_\index.test.js(在多个测试用例中使用advanceTimersByTime

import timer from "../index";

jest.useFakeTimers()

describe('测试 timer', () => {
  const fn = jest.fn();
  timer(fn);
  test('第一次测试 timer', () => {
    jest.advanceTimersByTime(3000)
    expect(fn).toHaveBeenCalledTimes(1)
  })

  test('第二次测试 timer', () => {
    jest.advanceTimersByTime(3000)
    expect(fn).toHaveBeenCalledTimes(1)
  })

  test('第三次测试 timer', () => {
    jest.advanceTimersByTime(3000)
    expect(fn).toHaveBeenCalledTimes(1)
  })
})

执行测试用例成功!(0~3 3~6 6~9 各执行一次)

调整参数:

import timer from "../index";

jest.useFakeTimers()

describe('测试 timer', () => {
  const fn = jest.fn();
  timer(fn);
  test('第一次测试 timer', () => {
    jest.advanceTimersByTime(2000)
    expect(fn).toHaveBeenCalledTimes(0)
  })

  test('第二次测试 timer', () => {
    jest.advanceTimersByTime(4000)
    expect(fn).toHaveBeenCalledTimes(2)
  })

  test('第三次测试 timer', () => {
    jest.advanceTimersByTime(3000)
    expect(fn).toHaveBeenCalledTimes(1)
  })
})

执行测试用例成功!(0~2 没有执行 2~6 执行两次 6~9 执行一次)

调整参数:

import timer from "../index";

jest.useFakeTimers()

describe('测试 timer', () => {
  const fn = jest.fn();
  timer(fn);
  test('第一次测试 timer', () => {
    jest.advanceTimersByTime(2000)
    expect(fn).toHaveBeenCalledTimes(0)
  })

  test('第二次测试 timer', () => {
    jest.advanceTimersByTime(2000)
    expect(fn).toHaveBeenCalledTimes(1)
  })

  test('第三次测试 timer', () => {
    jest.advanceTimersByTime(5000)
    expect(fn).toHaveBeenCalledTimes(2)
  })
})

执行测试用例成功!(0~1 没有执行 1~2 没有执行 2~9 执行三次)

从这三次测试调整中可以发现,toHaveBeenCalledTimes 统计的是每个测试用例里的 fn 调用次数,而 advanceTimersByTime 之间从前往后是相互叠加的

若是想要隔离这种影响,可以使用钩子函数

编辑 Jest\src\lesson11_tests_\index.test.js

import timer from "../index";

beforeEach(() => {
  jest.useFakeTimers();
})
describe('测试 timer', () => {
  test('第一次测试 timer', () => {
    const fn = jest.fn();
    timer(fn);
    jest.advanceTimersByTime(2000)
    expect(fn).toHaveBeenCalledTimes(0)
  })

  test('第二次测试 timer', () => {
    const fn = jest.fn();
    timer(fn);
    jest.advanceTimersByTime(2000)
    expect(fn).toHaveBeenCalledTimes(1)
  })

  test('第三次测试 timer', () => {
    const fn = jest.fn();
    timer(fn);
    jest.advanceTimersByTime(5000)
    expect(fn).toHaveBeenCalledTimes(2)
  })
})

执行测试用例,只有第一个成功!成功隔离(这里虚晃一枪,请看到最后)

注意使用了钩子函数之后,只有在测试用例中调用的定时器才是经过mock的!

来个烧脑的,编辑 Jest\src\lesson11_tests_\index.test.js(将 fn 的定义放在外边)

import timer from "../index";

beforeEach(() => {
  jest.useFakeTimers();
})
describe('测试 timer', () => {
  const fn = jest.fn();
  test('第一次测试 timer', () => {
    timer(fn);
    jest.advanceTimersByTime(2000)
    expect(fn).toHaveBeenCalledTimes(0)
  })

  test('第二次测试 timer', () => {
    timer(fn);
    jest.advanceTimersByTime(2000)
    expect(fn).toHaveBeenCalledTimes(1)
  })

  test('第三次测试 timer', () => {
    timer(fn);
    jest.advanceTimersByTime(5000)
    expect(fn).toHaveBeenCalledTimes(2)
  })
})

执行测试用例,前两个成功!最后一个:

Expected number of calls: 2
Received number of calls: 5

执行过程:


0~2
第一个函数执行,第一个定时器触发但没有执行完 0

2~4
第一个函数执行,第一个定时器执行完,第二个定时器触发但没有执行完 1
第二个函数执行,,第一个定时器触发但没有执行完 0

4~9
第一个函数执行,第二个和第三个定时器执行完 2
第二个函数执行,第一个和第二个定时器执行完 2
第三个函数执行,第一个定时器执行完 1

并没有视频课程中所说的隔离。。。但是功能理解了,over


本文仅作记录, 实战要点待后续专文总结,敬请期待。。。文章来源地址https://www.toymoban.com/news/detail-826868.html

到了这里,关于【实战】二、Jest难点进阶(三) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(七)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端自动化测试(二)Vue Test Utils + Jest

    项目会从快速迭代走向以维护为主的状态,因此引入自动化测试能有效减少人工维成本 。 自动化的收益 = 迭代次数 * 全手动执行成本 - 首次自动化成本 - 维护次数 * 维护成本 对于自动化测试,相对于发现未知问题,更倾向于避免可能的问题。 (1) 单元测试 单元测试(unit t

    2024年02月08日
    浏览(42)
  • react+jest+enzyme配置及编写前端单元测试UT

    安装相关库: 首先,使用npm或yarn安装所需的库。 配置Jest: 在项目根目录下创建一个 jest.config.js 文件,并配置Jest。 在上述配置中,设置了 setupFilesAfterEnv 为 src/setupTests.js ,指定了测试环境为 jsdom ,并设置了模块名称映射以处理CSS和LESS文件。 创建 setupTests.js 文件: 在项目

    2024年02月15日
    浏览(50)
  • Jest | 测试框架实战之-测试用例编写与覆盖率解读

    通常写完库的测试用例,总要跑跑覆盖率,看看测试用例写得如何,jest刚好也支持查看覆盖率,对应的指令是:jest --coverage。当然在继续往下看,如果还没搭建jest环境,可以先搭建,毕竟实践出真知。 如何编写测试用例,已经存在很多教程,官方也有非常多例子,因此这里

    2024年02月03日
    浏览(46)
  • Web自动化测试进阶:网页中难点之等待机制 —— 强制等待,隐式等待

    为什么要添加等待 避免页面未渲染完成后操作,导致的报错 经常会遇到报错:selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {\\\"method\\\":\\\"xpath\\\",\\\"selector\\\":\\\"//*[text()=\\\'个人中心\\\']\\\"} 页面还在加载时,就在进行查收元素,此时元素还没显示加载出来,而报

    2024年02月05日
    浏览(73)
  • 40个web前端实战项目,练完即可就业,从入门到进阶,基础到框架,html_css【附视频+源码】

    当下前端开发可以说是一个比较火的职业,所以学习的人比较多,不管是培训还是自学都是希望通过前端可以找到一份好的工作,但是很多自学的朋友在自学过程中有些盲目,不仅大大降低了学习的效率,而且也会打击自己的学习热情。 那么当我们学习了前端的一部分知识之

    2023年04月09日
    浏览(65)
  • 前端必学的CSS3波浪效果演示

    使用 translateX 和 translateZ 属性创建波浪效果: 使用场景: 适用于需要在X轴上平移和在Z轴上应用3D变换的波浪效果。 可以用于创建具有起伏效果的海浪、水面波纹等效果。 优点: 通过3D变换,可以实现更加真实的波浪效果。 可以通过调整 translateX 和 translateZ 的值来控制波浪

    2024年02月02日
    浏览(49)
  • 【前端进阶】前端安全:从入门到实践

    前言: Web应用程序的广泛使用,使得Web安全变得越来越重要。随着Web技术的不断发展和Web应用程序的复杂性增加,越来越多的前端安全漏洞受到广泛关注。为了保护Web应用程序和用户数据,我们需要了解和掌握前端安全的知识和实践。 在本文中,我们将介绍前端安全的基本

    2024年02月12日
    浏览(48)
  • 什么是 Jest ? Vue2 如何使用 Jest 进行单元测试?Vue2 使用 Jest 开发单元测试实例

    Jest 是一个流行的 JavaScript 测试框架,由 Facebook 开发并维护,专注于简单性和速度。它通常用于编写 JavaScript 和 TypeScript 应用程序的单元测试、集成测试和端到端测试。 特点: 简单易用: Jest 提供简洁的 API 和易于理解的语法,使得编写测试用例变得简单快捷。 零配置:

    2024年01月25日
    浏览(54)
  • 【前端】ECMAScript6从入门到进阶

    1.ES6简介及环境搭建 1.1.ECMAScript 6简介 (1)ECMAScript 6是什么 ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。 (2)ECMAScript 和 JavaScript 的关系 E

    2024年02月07日
    浏览(43)
  • 前端Vue入门-day06-路由进阶

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 路由的封装抽离 声明式导航 导航链接  两个类名  自定义高亮类名  跳转传参 1. 查询参数传参 2. 动态路由传参 两种传参方式的区别  Vue路由  重定向 404 编程式导航

    2024年02月14日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包