为什么要做单元测试

  作为一个前端工程师,我是很想去谢单元测试的,因为每天的需求很多,还要去编写测试代码,感觉时间都不够用了。

  不过最近开发了一个比较复杂的项目,让我感觉一旦项目大了、复杂了,而且还是多人维护一个应用,编写测试代码,

  还是很有必要的。毕竟这样做完之后,后边的维护会轻松很多。

  单元测试

  测试代码的最小单元,一个函数就是一个单元

  测试工具

  主要用到的测试工具是 jest 和 enzyme

  jest 、 enzyme 介绍

  jest 是 facebook 发布的一个开源的,基于 jasmine 框架的 javascript 单元测试工具它提供了很多有效的功能,

  包含了内置的测试环境的 DOM API 来操作 Dom、断言库、mock 等功能,并且 jest 是 react 的官网上面推荐

  的工具。

  enzyme 是 Airbnb 开源的 react 测试类库,提供了一套简洁强大的 api ,可以通过 jq 的风格进行 dom 处理,

  还可以引用一些其他的 dom 操作库。

  react 单元测试的搭建

  react 项目是基于 webpack + babel 来进行构建的。

  安装 npm 包

  首先需要添加一些 jest + enzyme 的 npm 包

  1. yarn add jest enzyme babel-jest regenerator-runtime react-test-renderer

  

  enzyme 需要安装对应的 react 的 adapter 版本

  1. yarn add enzyme-adapter-react-16

  

  

  配置文件

  1、package.json

  1. "scripts": {
  2. "test": "jest --colors --coverage"
  3. },   

  添加颜色和现实覆盖率

  .babelrc 文件

  

  1. "env": { // 单元测试下配置
  2. "test": {
  3. "presets": [
  4. "react",
  5. "react-optimize",
  6. [
  7. "env",
  8. {
  9. "modules": "commonjs", // 主要是添加这个
  10. "debug": true,
  11. "useBuiltIns": false,
  12. "targets": {
  13. "browsers": "defaults"
  14. }
  15. }
  16. ],
  17. "stage-0"
  18. ]
  19. }
  20. }

  

  因为测试环境的在 babel 中的配置 dev 为 test。

  所以这里需要特殊配置,modules 的形式是 commonjs

  添加jest配置文件jest.config

  1. module.exports = {
  2. roots: ['<rootDir>/__test__/', '<rootDir>/src/'], // 测试的目录
  3. modulePaths: ['<rootDir>'],
  4. coveragePathIgnorePatterns: ['/node_modules/', '/tests/setup.js'], //忽略统计覆盖率的文件
  5. // bail: true,
  6. // testRegex: '', // 后缀名称
  7. // testPathIgnorePatterns: 'est', // 忽略路径
  8. // moduleNameMapper: { // 与测试无关的资源文件同意mock 掉,这样在import 的时候就不会真的引入这些文件
  9. // '^import?': '<rootDir>/build/jestImportMock.js',
  10. // '\\.(css|less|gif|jpg|jpeg|png)$': '<rootDir>/build/jestStyleMock.js',
  11. // },
  12. };

  

  

  jest 详解

  

  1、简单测试结构

  1. function sum(a,b){
  2. return a+b;
  3. }
  4.  
  5. it('adds 1 + 2 to equal 3', () => {
  6. expect(sum(1, 2)).toBe(3);
  7. });

  

  2、异步的测试结构

  1. async function sum (a,b){
  2. return a+b;
  3. }
  4.  
  5. it('adds 1 + 2 to equal 3',async () => {
  6. const total = await sum(1,2)
  7. expect(total).toBe(3);
  8. });

  

  3、Mock Function 结构

  1. function forEach(items, callback) {
  2. for (let index = 0; index < items.length; index++) {
  3. callback(items[index]);
  4. }
  5. }
  6.  
  7. const mockCallback = jest.fn(x => 42 + x);
  8. forEach([0, 1], mockCallback);
  9.  
  10. // 可以 mockCallback.mock 访问 mockCallback 状态

  

  1、jest.fn 用来创建一个 mock function

  2、mockCallback.mock 可以访问 mock function 的状态

  mock 的属性:

  calls : 调用的参数数组,保存了每次调用的入参

  calls.length : 调用次数

  calls[0][0] : 第一次调用的时候的第一个参数

  results:调用的结果数组

  results[0].value : 第一次调用的返回结果

  

  执行 mock function

  1. const myMock = jest.fn();
  2. console.log(myMock());
  3. // > undefined
  4.  
  5. myMock
  6. .mockReturnValueOnce(10)
  7. .mockReturnValueOnce('x')
  8. .mockReturnValue(true);
  9.  
  10. console.log(myMock(), myMock(), myMock(), myMock());
    //10 x true

  1、用 mockRetrunValueOnce(value) 来预先设置函数的返回值

  2、mymock() 返回预先设置的值

  异步请求的数据模拟

  1. let fetch = {
  2. get:() =>{}
  3. }
  4. jest.mock(fetch)
  5. fetch.get.mockResolvedValue({data:{},status:0})
  6. fetch.get(url,options)
  7. // {data:{},status:0}

  

  

  4、常用全局方法

  describe(message,()=>{})  : 创建块

  it(message,()=>{}) : 测试单元

   

  5、ecpect 常用方法

  expect(value) : 注入测试单元

   expect.extend({}) : 拓展 expect 方法

  1. expect.extend({
  2. toBeBetween(received, arg1, arg2) {
  3. const min = arg1;
  4. const max = arg2;
  5. if (received > min && received < max) {
  6. return {
  7. message: '',
  8. pass: true,
  9. };
  10. }
  11. return {
  12. message: `received is between in ${min} - ${max}`,
  13. pass: true,
  14. };
  15. },
  16. });
  17.  
  18. expect(99).toBeBetween(1,100)

  

  expect.anything()  : 返回除了 null 和 undefined 意外的任何类型数据

  expect.any(Number/String) : 任意 数字/字符串

   expect.assertions(num) : 确定在块中调用几次异步

  toBe(value) : 等于

  toHaveBeenCalled() : 确定函数调用

  toHaveBeenCalledTime(number) : 确定被调用的次数

  toHaveBeenCalledWith(arg1,arg2) :取保调用的函数的值

  toHaveBeenNthCalledWith(num,arg2) : 确保第几个参数

  toHaveRetruned() :确保有返回值

  toHave[:Nth]RetrunedWith([:num,]arg) : 确保某一个有返回值

  toContain(item) : 数组中是否包含 

   toMatch(regex) :正则表达式

  

  enzyme

  enzyme 一共有四个大的 api ( shallow 、mount 、render 、selectors )。

   通过这四个 api 可以对 react 组件进行操作。

   我们可以通过类似于 jquery 的操作来进行 test 。

  

  

react 单元测试 (jest+enzyme)的更多相关文章

  1. react: typescript jest && enzyme

    Install Jest 1.install jest dependencies jest @types/jest ts-jest -D 2.jest.config.js module.exports ...

  2. 搭建 Jest+ Enzyme 测试环境

    1.为什么要使用单元测试工具? 因为代码之间的相互调用关系,又希望测试过程单元相互独立,又能正常运行,这就需要我们对被测函数的依赖函数和环境进行mock,在测试数据输入.测试执行和测试结果检查方面存在 ...

  3. react typescript jest config (一)

    1. initialize project create a folder project Now we'll turn this folder into an npm package. npm in ...

  4. React单元测试——十八般兵器齐上阵,环境构建篇

    一个完整.优秀的项目往往离不开单元测试的环节,就 github 上的主流前端项目而言,基本都有相应的单元测试模块. 就 React 的项目来说,一套完整的单元测试能在在后续迭代更新中回归错误时候给与警 ...

  5. 如何为我的VUE项目编写高效的单元测试--Jest

    Unit Testing(单元测试)--Jest 一个完整的测试程序通常由几种不同的测试组合而成,比如end to end(E2E)测试,有时还包括整体测试.简要测试和单元测试.这里要介绍的是Vue中 ...

  6. jest enzyme unit test react

    1. 测试类型 单元测试:指的是以原件的单元为单位,对软件进行测试.单元可以是一个函数,也可以是一个模块或一个组件,基本特征就是只要输入不变,必定返回同样的输出.一个软件越容易些单元测试,就表明它的模 ...

  7. Jest+Enzyme React js/typescript测试环境配置案例

    本文案例github:https://github.com/axel10/react-jest-typescript-demo 配置jest的react测试环境时我们可以参考官方的配置教程: http ...

  8. [React] Use Jest's Snapshot Testing Feature

    Often when testing, you use the actual result to create your assertion and have to manually update i ...

  9. 单元测试jest部署

    引入jest需安装的基础插件: 基础插件 @babel/core 编译工具核心模块包 @babel/preset-env 编译工具,支持es2015特性的编译打包工具包 babel-jest 对.js ...

随机推荐

  1. BFS(最短路) HDU 2612 Find a way

    题目传送门 /* BFS:和UVA_11624差不多,本题就是分别求两个点到KFC的最短路,然后相加求最小值 */ /***************************************** ...

  2. vue中数据接收成功,页面渲染失败

    1.vue中数据接收成功,页面渲染失败.代码如下 经过查找资料修改代码为 或是 原因是: 由于 JavaScript 的限制, Vue 不能检测以下变动的数组: 当你利用索引直接设置一个项时,例如:  ...

  3. javascript 到将来某个时间(2020-5-20)的倒计时

    function countDown(dateStr){ var end = +new Date(dateStr), start = +new Date(), during = Math.floor( ...

  4. Java_数组1_16.5.12

    声明整型数组a: int[] a; 这时,只声明了变量a,还应该使用new运算符创建数组: int[] a=new int [100];(数组长度不要求是一个常量:new int[n]会创建一个长度为 ...

  5. 踩过好多次的坑 - ajax访问【mango】项目的service

    这个坑真的是踩过好多次了,好记性不如烂笔头,我总是太高估我的记忆力,这次真的是要写下来了. 项目是用的seam框架 + hibernate搭建的,架构是前辈们搭好的劳动成果,在配置service的访问 ...

  6. spring思想分析

    摘要: EveryBody in the world should learn how to program a computer...because it teaches you how to th ...

  7. 15Microsoft SQL Server 数据库维护

    Microsoft SQL Server 数据库维护 2.6.1数据库联机与脱机 --联机:该状态为数据库正常状态,也就是我们常看到的数据库的状态,该状态下的数据库处于可操作状态,可以对数据库进行任何 ...

  8. Gym - 101670H Dark Ride with Monsters(CTU Open Contest 2017 贪心)

    题目: A narrow gauge train drives the visitors through the sequence of chambers in the Dark Ride attra ...

  9. 洛谷 P1280 尼克的任务 (线性DP)

    题意概括 线性资源分配的问题,因为空闲的时间大小看后面的时间(反正感觉这个就是个套路)所以从后往前DP. 转移方程 如果当前时刻没有工作 f[i]=f[i+1]+1 如果当前时刻有工作 f[i]=ma ...

  10. 经典书籍---MySQL经典书籍下载

    以下是一些经典的MySQL书籍电子版,括号内为提取码,若需自取. 欢迎阅读纸质版,尊重作者版权 高性能MySQL_中文版 [ hre3 ] 高性能MySQL_英文版[ m2xj ] MySQL技术内幕 ...