Jest单元测试:玩转代码的小捉迷藏!

嗨,码农小伙伴们!在这个金秋十月,国庆与中秋重叠,我们有一个特殊的任务——通过 Jest 单元测试,找到代码的神秘“中秋蛋糕”!这是一个简单又有趣的冒险,就像在中秋晚会上找月亮一样容易。让我们一起来挖掘代码的宝藏,同时送上国庆和中秋的双重祝福吧!

Jest

Jest 是什么?

Jest 是一个流行的 JavaScript 测试框架,专注于简化和改进代码的测试流程。它由 Facebook 开发并维护,具有以下特点:

1、易用性:Jest 提供了一个简单而强大的测试框架,使得编写和运行测试变得非常容易。

2、自动化:它自动发现和运行测试,无需复杂的配置,可立即开始测试代码。

3、断言库:Jest 集成了强大的断言库,用于验证代码的预期行为,帮助您捕获潜在的问题。

4、模拟和模拟函数:Jest 支持模拟测试环境,使得模拟函数和模块变得容易,从而提高了测试的效率。

5、快照测试:Jest 允许您轻松地创建和维护快照测试,以确保 UI 组件的渲染和结构不会意外更改。

6、并发测试:它可以并行运行测试,提高了测试的速度,特别适用于大型代码库。

7、丰富的插件生态系统:Jest 的生态系统中有许多插件和扩展,可以满足各种不同测试需求。

为什么选择 Jest?

Jest 在开发社区中广受欢迎,因为它具备了一切进行前端和后端 JavaScript 测试所需的功能,并且非常易于入门。它不仅用于单元测试,还可用于集成测试和端到端测试。Jest 的自动化特性和强大的功能使得测试变得更加轻松、高效,有助于提高代码质量并减少潜在的问题。无论您是前端开发者还是后端开发者,Jest 都是一个值得考虑的测试工具。

简介

Jest 是一个基于Jasmine和Mocha的测试框架,它提供了一套易于使用的API,可用于编写简洁、可维护的测试用例。Jest还集成了断言库、模拟函数工具和代码覆盖率报告等功能。

安装

首先,确保你已经在项目目录下初始化npm。然后,使用以下命令安装 Jest :

npm install --save-dev jest
  • 1

安装完成后,你可以在package.json中的"scripts"部分添加一个命令,以便更方便地运行测试:

"scripts": {
  "test": "jest"
}

接下来我们就可以开始愉快的编写测试用例了。

编写测试用例

首先创建一个名为sum.js的文件,其中包含以下函数:

// sum.js
function sum(a, b) {
  return a + b;
}

module.exports = sum;

现在,创建一个名为sum.test.js的文件,以编写针对sum函数的测试用例:

// sum.test.js
const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

在这个测试用例中,我们使用了test全局函数来定义一个测试。其中,第一个参数是测试的描述,第二个参数是一个函数,在这个函数内我们编写测试逻辑。使用expect函数来断言我们的测试结果。

运行测试

现在可以运行测试了。在终端中运行以下命令:

npm test
  • 1

断言

Jest提供了丰富的断言方法,用于验证预期结果。以下是一些常用的断言方法:

expect(value).toBe(expected): 检查value是否等于expected。

expect(value).toEqual(expected): 检查value是否深度等于expected。

expect(value).toBeNull(): 检查value是否为null。

expect(value).toBeDefined(): 检查value是否已定义。

expect(value).toBeTruthy(): 检查value是否为真值。

expect(value).toBeFalsy(): 检查value是否为假值。

expect(value).not.toBe(expected): 检查value是否不等于expected。

异步测试

在处理异步逻辑时,Jest提供了多种方法来编写和处理异步测试。
常用的有两种方式:

使用async和await关键字:

test('async test', async () => {
  const data = await fetchData();
  expect(data).toEqual(expectedData);
});

使用done参数:

test('callback test', (done) => {
  fetchData((data) => {
    expect(data).toEqual(expectedData);
    done();
  });
});

Mocking

在测试中,我们经常会需要模拟函数或模块的行为。Jest提供了内置的模拟函数工具来实现此功能。

以下是一个使用Jest的模拟函数的示例:

function fetchData(callback) {
  // 假设这是一个异步操作
  setTimeout(() => {
    callback('Hello Jest!');
  }, 1000);
}

test('mocking test', () => {
  const mockCallback = jest.fn();
  fetchData(mockCallback);

  expect(mockCallback).toHaveBeenCalledTimes(1);
  expect(mockCallback).toHaveBeenCalledWith('Hello Jest!');
});

在上面的示例中,我们使用jest.fn()创建一个模拟函数mockCallback,然后将其作为回调函数传递给fetchData函数。通过使用jest.fn(),我们可以跟踪这个模拟函数的调用次数和传入的参数,以进行断言。

代码覆盖率

代码覆盖率是衡量测试覆盖范围的指标。Jest提供了内置的代码覆盖率工具,可以帮助你分析测试覆盖情况。

通过在package.json中添加以下配置,可以生成代码覆盖率报告:

"scripts": {
  "test": "jest --coverage"
}

运行npm test命令后,Jest将会生成一个代码覆盖率报告,展示你的测试覆盖情况。

高级配置

Jest提供了丰富的配置选项,用于满足项目的需求。你可以在项目根目录下创建一个jest.config.js文件来配置Jest。

以下是一个简单的配置示例:

// jest.config.js
module.exports = {
  verbose: true,
  testEnvironment: 'node',
  coverageDirectory: 'coverage',
  collectCoverageFrom: ['src/**/*.js'],
};
  • 1

异常测试

在测试代码中,我们需要确保正确地处理异常情况。Jest提供了多个断言方法来处理异常。

function divide(a, b) {
  if (b === 0) {
    throw new Error('Divide by zero');
  }
  return a / b;
}

test('divide should throw an error when dividing by zero', () => {
  expect(() => {
    divide(10, 0);
  }).toThrow('Divide by zero');
});

在上面的示例中,我们使用toThrow断言方法来验证代码是否会抛出预期的错误。

测试异步代码的错误

当测试异步代码时,必须确保能够捕捉到异步操作中的错误。Jest提供了几种方式来处理这种情况。

async function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('Fetch error');
    }, 1000);
  });
}

test('fetchData should throw an error', async () => {
  expect.assertions(1);
  try {
    await fetchData();
  } catch (error) {
    expect(error).toEqual('Fetch error');
  }
});

在上面的示例中,我们使用expect.assertions来确保至少有一个断言被执行。然后使用try-catch块捕捉到fetchData函数中的错误,并使用断言验证错误的值。

测试对象的方法调用次数

有时候我们需要确保对象的方法被正确调用了指定的次数。Jest提供了用于检查模拟函数调用次数的方法。

class Counter {
  constructor() {
    this.count = 0;
  }

  increment() {
    this.count++;
  }
}

test('Counter increment method should be called twice', () => {
  const counter = new Counter();
  counter.increment();
  counter.increment();
  const incrementMock = jest.spyOn(counter, 'increment');

  expect(incrementMock).toHaveBeenCalledTimes(2);
});

在上面的示例中,我们使用jest.spyOn来监视Counter类的increment方法,然后通过调用两次increment方法,并使用toHaveBeenCalledTimes断言方法验证方法被正确调用了两次。

测试组件交互

在测试React组件时,我们通常需要模拟用户交互和验证组件的行为。Jest提供了一些方法和工具来帮助测试React组件。

import { render, fireEvent } from '@testing-library/react';
import Button from './Button';

test('Button click should trigger callback', () => {
  const handleClick = jest.fn();
  const { getByText } = render(<Button onClick={handleClick}>Click me</Button>);
  const button = getByText('Click me');
  fireEvent.click(button);

  expect(handleClick).toHaveBeenCalled();
});

在上面的示例中,我们使用@testing-library/react库中的render函数和fireEvent工具来渲染和测试组件。然后使用jest.fn创建一个模拟函数来监视回调函数的调用,并通过模拟点击按钮来触发回调,并使用toHaveBeenCalled断言方法来验证回调函数是否被调用。

快照测试

快照测试是一种用于捕捉组件或数据结构的初始渲染和状态的测试方法。Jest的toMatchSnapshot方法可以用来创建和比较快照。

import renderer from 'react-test-renderer';
import MyComponent from './MyComponent';

test('MyComponent snapshot', () => {
  const tree = renderer.create(<MyComponent />).toJSON();
  expect(tree).toMatchSnapshot();
});
  • 1

在第一次运行测试时,Jest将创建一个快照文件,然后在后续运行时将快照与新的渲染结果进行比较。这有助于检测组件是否发生了意外更改。

参数化测试

有时我们需要测试一组相似的输入,可以使用参数化测试来减少代码重复。

const testData = [
  { input: 2, expected: 4 },
  { input: 3, expected: 9 },
  { input: 4, expected: 16 },
];

test.each(testData)('square(%i) should return %i', (input, expected) => {
  expect(square(input)).toBe(expected);
});
  • 1

在上面的示例中,我们使用test.each方法来定义一个参数化测试,它会根据不同的输入值多次运行相同的测试代码,从而避免了重复的测试用例。

自定义匹配器

Jest允许你创建自定义匹配器,以便更容易地编写特定于应用程序的断言。

expect.extend({
  toBeValidEmail(received) {
    const regex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}$/i;
    const pass = regex.test(received);
    if (pass) {
      return {
        message: () => `expected ${received} not to be a valid email`,
        pass: true,
      };
    } else {
      return {
        message: () => `expected ${received} to be a valid email`,
        pass: false,
      };
    }
  },
});

test('email validation', () => {
  expect('test@example.com').toBeValidEmail();
  expect('invalid-email').not.toBeValidEmail();
});
  • 1

在上面的示例中,我们创建了一个自定义匹配器toBeValidEmail,用于验证字符串是否为有效的电子邮件地址。这使得我们可以使用自定义的断言来验证应用程序的特定行为。

使用beforeEach和afterEach

beforeEach和afterEach函数允许你在每个测试用例之前和之后执行特定的操作,例如设置和清理测试环境。

let counter = 0;

beforeEach(() => {
  counter++;
});

afterEach(() => {
  counter = 0;
});

test('increment counter', () => {
  expect(counter).toBe(1);
});

test('reset counter', () => {
  expect(counter).toBe(1);
  counter = 5;
  expect(counter).toBe(5);
});
  • 1

在上面的示例中,beforeEach用于在每个测试用例之前递增counter,而afterEach用于在每个测试用例之后将counter重置为0,以确保测试的隔离性。

测试组件的生命周期方法

如果你使用 React 或其他支持生命周期方法的库,你可以使用 jest 和 enzyme(或其他库)来测试组件的生命周期方法。

import React from 'react';
import { mount } from 'enzyme';
import MyComponent from './MyComponent';

test('componentDidMount is called', () => {
  const componentDidMountSpy = jest.spyOn(MyComponent.prototype, 'componentDidMount');
  const wrapper = mount(<MyComponent />);
  expect(componentDidMountSpy).toHaveBeenCalled();
  componentDidMountSpy.mockRestore();
});

在上面的示例中,我们使用 enzyme 来挂载一个 React 组件,并使用 jest.spyOn 来监视 componentDidMount 生命周期方法的调用。

模拟时间

有时候需要测试与时间相关的操作,比如 setTimeout 或 setInterval。Jest 提供了一种模拟时间的方式。

jest.useFakeTimers();

test('setTimeout test', () => {
  const callback = jest.fn();
  setTimeout(callback, 1000);

  jest.advanceTimersByTime(1000);

  expect(callback).toHaveBeenCalled();
});

在这个示例中,我们使用 jest.useFakeTimers() 来模拟时间,并使用 jest.advanceTimersByTime 来快进时间以触发 setTimeout 回调函数。

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

在这里插入图片描述

软件测试面试文档

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

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

springboot208基于springboot物流管理系统

基于spring boot物流管理系统设计与实现 摘 要 社会发展日新月异&#xff0c;用计算机应用实现数据管理功能已经算是很完善的了&#xff0c;但是随着移动互联网的到来&#xff0c;处理信息不再受制于地理位置的限制&#xff0c;处理信息及时高效&#xff0c;备受人们的喜爱。…

大数据Kafka--概述

文章目录 概述定义消息队列传统消息队列的应用场景消息队列的两种模式 Kafka基础架构 Kafka快速入门安装部署集群规划集群部署集群启停脚本 Kafka命令行操作主题命令行操作生产者命令行操作消费者命令行操作 概述 定义 消息队列 目前企业中比较常见的消息队列产品主要有 Kafk…

PLC_博图系列☞基本指令“插入输入”

PLC_博图系列☞基本指令“插入输入” 文章目录 PLC_博图系列☞基本指令“插入输入”背景介绍插入输入说明参数示例 关键字&#xff1a; PLC、 西门子、 博图、 Siemens 、 插入输入 背景介绍 这是一篇关于PLC编程的文章&#xff0c;特别是关于西门子的博图软件。我并不是专…

LeetCode每日刷题:101. 对称二叉树

题目&#xff1a; 解题思路&#xff1a;可以新写一个函数&#xff0c;从root开始&#xff0c;root的left的头结点将记为lefttree&#xff08;左子树&#xff09;,root的lright的头结点将记为righttree&#xff08;右子树&#xff09;&#xff0c; 然后递归左子树的root.left与右…

搭建sql-labs靶机环境

phpstudy&#xff08;小皮面板&#xff09; 先下载phpstudy&#xff08;小皮面板&#xff09;软件&#xff0c;方便我们快速搭建环境&#xff0c;该软件程序包集成最新的ApachePHPMySQLngix,一次性安装,无须配置即可使用,是非常方便、好用的PHP调试环境.该程序不仅包括PHP调试…

C++笔记:OOP三大特性之继承

文章目录 一、继承的概念和定义1.1 概念1.2 定义格式1.3 继承关系和访问限定符 二、基类和派生类对象赋值兼容转换2.1 类型转换存在临时对象的意义2.2 赋值兼容转换不会产生临时变量 三、继承中的作用域四、派生类中的默认成员函数4.1 构造4.2 拷贝构造4.3 赋值重载4.4 析构 五…

【进程创建】

目录 进程创建的方式查看进程pid 调用系统调用创建子进程fock函数做了的工作子进程刚开始创建的状态 一个变量&#xff0c;两个不同的值创建子进程的作用 进程创建的方式 1.在操作系统上输入的指令。 2.已经启动的软件。 3.程序员在代码层面上调用系统调用创建进程。 linux中第…

centos6安装

前期准备 官网 选择download 选择isos 选择mininal.iso下载 安装 打开vmware 输入root和密码登录

Block Coordinate Descent算法的部分构造技巧

文章目录 构造的目的定理另一篇中对于该定理的表述出处 构造的目的 通过增加辅助变量&#xff0c;使原来的非凸问题变为关于各个变量的凸子问题&#xff0c;交替优化各个辅助变量。 定理 Define an m m m by m m m matrix function E ( U , V ) ≜ ( I − U H H V ) ( I …

工具分享:Corn表达式在线生成工具介绍

无极低码 &#xff1a;https://wheart.cn Corn表达式在线生成工具介绍 在现代的信息技术领域中&#xff0c;定时任务是一个不可或缺的功能。无论是为了定期清理缓存、发送邮件、还是执行其他自动化任务&#xff0c;我们都需要一个高效、便捷的定时工具。而在众多的定时工具中…

Microsoft PowerToys:自定义 Windows 的实用程序

Microsoft PowerToys&#xff1a;自定义 Windows 的实用程序 Microsoft PowerToys 是一组实用程序&#xff0c;供高级用户调整和简化其 Windows 体验以提高工作效率。 微软官方地址为&#xff1a;https://learn.microsoft.com/en-us/windows/powertoys/&#xff0c;其github源…

springboot207基于springboot的实习管理系统

实习管理系统的设计与实现 摘要 近年来&#xff0c;信息化管理行业的不断兴起&#xff0c;使得人们的日常生活越来越离不开计算机和互联网技术。首先&#xff0c;根据收集到的用户需求分析&#xff0c;对设计系统有一个初步的认识与了解&#xff0c;确定实习管理系统的总体功…

qt-OPENGL-星系仿真

qt-OPENGL-星系仿真 一、演示效果二、核心程序三、下载链接 一、演示效果 二、核心程序 #include "model.h"Model::Model(QOpenGLWidget *_glWidget) { glWidget _glWidget;glWidget->makeCurrent();initializeOpenGLFunctions(); }Model::~Model() {destroyV…

HashMap 源码学习-jdk1.8

1、一些常量的定义 这里针对MIN_TREEIFY_CAPACITY 这个值进行解释一下。 java8里面&#xff0c;HashMap 的数据结构是数组 &#xff08;链表或者红黑树&#xff09;&#xff0c;每个数组节点下可能会存在链表和红黑树之间的转换&#xff0c;当同一个索引下面的节点超过8个时…

Elastic Stack--01--简介、安装

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1. Elastic Stack 简介为什么要学习ESDB-Engines搜索引擎类数据库排名常年霸榜![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/051342a83f574c8c910cda…

【软件架构】02-复杂度来源

1、性能 1&#xff09;单机 受限于主机的CPU、网络、磁盘读写速度等影响 在多线程的互斥性、并发中的同步数据状态等&#xff1b; 扩展&#xff1a;硬件资源、增大线程池 2&#xff09;集群 微服务化拆分&#xff0c;导致调用链过长&#xff0c;网络传输的消耗过多。 集…

【Web前端笔记10】CSS3新特性

10 CSS3新特性 &#xff11;、圆角 &#xff12;、阴影 &#xff08;&#xff11;&#xff09;盒阴影 &#xff13;、背景渐变 &#xff08;&#xff11;&#xff09;线性渐变&#xff08;主要掌握这种就可&#xff09; &#xff08;&#xff12;&#xff09;径向渐变 &…

滚雪球学Java(67):深入理解 TreeMap:Java 中的有序键值映射表

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java SE相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

C++学习之list容器

C++ list基本概念 在C++中,std::list是一个双向链表(doubly linked list)容器,它包含在 <list> 头文件中。下面是一些关于C++ std::list的基本概念: 双向链表结构:std::list是由多个节点组成的双向链表结构,每个节点包含数据元素和指向前一个节点和后一个节点的指…

ABCDE联合创始人BMAN确认出席Hack .Summit() 2024香港Web3盛会

ABCDE联合创始人和普通合伙人BMAN确认出席Hack .Summit() 2024&#xff01; ABCDE联合创始人和普通合伙人BMAN确认出席由 Hack VC 主办&#xff0c;并由 AltLayer 和 Berachain 联合主办&#xff0c;与 SNZ 和数码港合作&#xff0c;由 Techub News 承办的Hack.Summit() 2024区…