当前位置: 首页 > news >正文

(2.2w字)前端单元测试之Jest详解篇

Jest

Jest 概述

Jest是一个领先的JavaScript测试框架,特别适用于React和Node.js环境。由Facebook开发,它以简单的配置、高效的性能和易用性而闻名。Jest支持多种类型的测试,包括单元测试、集成测试和快照测试,后者用于捕获组件或数据结构的状态,以便于后续的比较和验证。Jest自动化模拟依赖项和异步代码测试,提高了测试的可靠性和灵活性。其并行测试执行机制显著加快了测试过程,而交互式监视模式则在开发过程中提供即时反馈。此外,Jest还提供内置的代码覆盖率工具,帮助开发者优化测试范围。因其强大的功能和广泛的社区支持,Jest成为现代JavaScript项目中不可或缺的测试工具。

Jest 环境配置

安装包

1、jest:这是 Jest 测试框架本身。

2、@types/jest:这是 Jest 的 TypeScript 类型定义,用于在使用 TypeScript 编写测试时提供类型检查和自动完成功能。

3、babel-jest:这是用于将 Jest 集成到使用 Babel 的项目中的插件。它允许 Jest 处理通过 Babel 转换的代码。

4、ts-jest:这是一个 Jest 转换器,用于处理 TypeScript 文件。它基本上允许 Jest 理解和运行 TypeScript 测试代码。

5、jest-transform-stub:这个插件用于处理非 JavaScript 资源(如 CSS 和图片)的导入,这在 Jest 测试中通常会被忽略或需要特殊处理。

npm install --save-dev jest @types/jest babel-jest ts-jest jest-transform-stub

6、@testing-library/jest-dom:提供一套针对 DOM 元素的 Jest 断言,非常适用于在测试 React 组件时使用。

7、@testing-library/react:用于测试 React 组件,它提供了渲染组件、查询 DOM 元素以及与组件交互的工具。

8、@testing-library/user-event:这个库用于模拟用户事件(如点击、输入等),可用于更逼真地测试用户交互。

npm install --save-dev @testing-library/jest-dom @testing-library/react @testing-library/user-event

9、eslint-plugin-jest:这是一个 ESLint 插件,提供针对 Jest 测试的特定规则,有助于保持测试代码的质量和一致性。

10、react-test-renderer:
这是一个用于渲染 React 组件为 JavaScript 对象的库,常用于 Jest 的快照测试。它可以在不需要 DOM 环境的情况下测试 React 组件的输出,这对于在 Node 环境下运行的 Jest 测试非常有用。

npm install --save-dev eslint-plugin-jest react-test-renderer

package.json

1、基本的运行测试用例配置,npm test即可运行

--watchAll:这个参数告诉 Jest 进入 “watch” 模式。在这个模式下, Jest 会监视项目中的文件变化。当修改并保存了代码文件(包括测试文件和被测试的源代码文件)时, Jest 会自动重新运行相关的测试。

--watchAll--watch 不同之处在于,--watchAll 会在初次运行时执行所有测试,而 --watch 只在检测到文件更改时运行相关测试。

"test": "jest --watchAll",

2、运行某个文件夹下的所有测试文件,src/tests代表文件夹路径

"test:folder": "jest --watchAll --testPathPattern=src/tests",

3、单独运行某个测试文件,src/renderer/login/loginApi.test.tsx代表需要测试的文件路径

"test:single": "jest --watchAll jest --findRelatedTests src/renderer/login/loginApi.test.tsx",
常见的 Jest 命令行操作

1、f 只会跑测试未通过的用例,再次点击 f 会取消当前模式。

2、o 只监听已改变的文件,如果存在多个测试文件,可以开启,会与当前 git 仓库中的提交进行比较,需要使用 git 来监听哪个文件修改了,也可以将 --watchAll 改为 --watch 只会运行修改的文件。

3、a 运行所有测试,如果在 watch 模式中使用了 f 或 o ,使用 a 可以恢复运行所有测试。

4、u 用于更新 Jest 快照测试中的快照。如果更改了渲染组件的输出,可以使用此命令更新快照。

5、w 显示 Jest watch 模式中的所有可用命令和选项的列表。

6、q 退出 Jest 的 watch 模式。

7、i 只会运行之前运行失败的测试文件,但提供更交互式的体验。

.babelrc

当使用 Jest 测试一个使用 Babel 编译的项目时,Jest 会通过这些配置来正确处理和理解 JavaScript 代码。

{// 设置插件集合"presets": [// 使用当前插件,可以进行转换// 数组的第二项为插件的配置项["@babel/preset-env",{// 根据 node 的版本号来结合插件对代码进行转换"targets": {"node": "current"}}]]
}

setupTests.js

该文件设置测试环境中的全局对象和模拟(mock)某些模块,在本项目中针对 Electron 和 Node.js 的相关模块进行模拟,以便在不依赖实际 Electron 或浏览器环境的情况下测试特定的功能。

/* eslint-disable no-undef */
const electronMock = require('./__Mock__/electronMock')global.window.require = jest.fn(moduleName => {if (moduleName === 'electron') {return electronMock}if (moduleName === '@electron/remote') {return {require: jest.fn(module => {// 模拟 Node.js 模块,如 fsif (module === 'fs') {return {} // 返回 fs 的模拟实现}// 其他模块模拟...}),}}
})
global.window.matchMedia =global.window.matchMedia ||function () {return {matches: false,addListener: function () {},removeListener: function () {},}}

jest.config.ts

jest.config.ts 是一个使用 TypeScript 编写的 Jest 配置文件。可以使用npx jest --init初始化命令来生成一个基本的配置文件。

export default {// 自动清除 mock 调用和实例clearMocks: true,// 开启代码覆盖率收集collectCoverage: true,// 代码测试覆盖率通过分析那些文件生成的,!代表不要分析collectCoverageFrom: ['**/*.{ts,js,tsx}', '!**/node_modules/**', '!**/vendor/**'],// 代码覆盖率报告的输出目录coverageDirectory: 'coverage',// 代码覆盖率的收集器,这里使用 V8 引擎coverageProvider: 'v8',// 代码覆盖率报告的格式coverageReporters: ['text-summary','lcov',],globals: {'ts-jest': {// 关闭 ts-jest 的诊断信息diagnostics: false,},},// 引入模块时,进行自动查找模块类型,逐个匹配moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'],// 模块名字使用哪种工具进行映射moduleNameMapper: {'^@/(.*)$': '<rootDir>/src/$1', //将 @/ 映射到 src/ 目录'\\.(css|less)$': 'jest-transform-stub','^localTypes$': '<rootDir>/src/types.ts','^localUtils$': '<rootDir>/src/utils/index.ts','^localConst$': '<rootDir>/src/utils/constants.ts','^Assets/(.*)$': '<rootDir>/assets/$1',},preset: 'ts-jest',rootDir: undefined,// 检测从哪个目录开始,rootDir 代表根目录roots: ['<rootDir>/src'],// 在运行测试之前执行的文件(设置测试环境)setupFilesAfterEnv: ['./setupTests.js'],// 测试运行的环境,会模拟 domtestEnvironment: 'jsdom',// 哪些文件会被认为测试文件testMatch: [// src 下的所有 __tests__ 文件夹中的所有的 js jsx ts tsx 后缀的文件都会被认为是测试文件'<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',// scr 下的所有以 .test/spec.js/jsx/ts/tsx 后缀的文件都会被认为是测试文件'<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}',],// 测试时忽略的路径testPathIgnorePatterns: ['\\\\node_modules\\\\'],// 测试文件中引用一下后缀结尾的文件会使用对应的处理方式transform: {'^.+\\.(t|j)s$': 'ts-jest','\\.svg$': '<rootDir>/__Mock__/svgTransform.js',},
}

__Mock__文件夹

文件夹用于存放模拟(mock)模块

自动模拟:当调用jest.mock('moduleName')时,Jest会查找__mocks__文件夹中名为 moduleName 的文件,并自动使用该文件中的模拟实现。这意味着不需要在每个测试文件中手动设置模拟。

第三方模块模拟:这个机制不仅适用于自定义模块,也适用于第三方模块。例如正在使用一个发送 fetch 请求的库,可以在 __mocks__文件夹中创建一个模拟,以避免在测试中发出真实的网络请求。

Mock

Mock fetch 或其他 HTTP 请求库的调用

待补充

Mock 函数

jest.fn()

Mock 第三方模块

待补充

全局函数 describe 和 it

describe 用于将测试分组,而 it 用于定义单个具体的测试用例。可以在 describe 块中放置多个 it 测试用例,也可以嵌套其他 describe 块以创建更详细的测试结构。

// 用于创建一个测试套件,将一组功能或逻辑相关的测试用例组织在一起
describe('测试输入框的校验规则', () => {// it 的第一个参数是一个字符串,描述了测试用例应该做什么,有助于代码的可读性和测试结果的理解it('输入正常', async () => {// ...});it('必填', async () => {// ...});it('仅支持汉字、字母、数字和-_%.', async () => {// ...})it('以数字、字母或汉字开头', async () => {// ...})it('限长', async () => {// ...})
});

断言 expect

用于验证代码的行为是否符合预期。 expect 函数接受一个参数———想要测试的值。然后,expect 返回一个“期望对象”,这个对象提供了一系列“匹配器”(matcher)方法,用于声明对这个值的期望。

describe('测试输入框的校验规则', () => {it('必填', async () => {// ...expect(message).toBeInTheDocument()})it('仅支持汉字、字母、数字和-_%.', async () => {// ...expect(message).toBeInTheDocument()})it('以数字、字母或汉字开头', async () => {// ...expect(message).toBeInTheDocument()})it('限长', async () => {// ...expect(message).toBeInTheDocument()})it('输入正常', async () => {// ...await waitFor(() => {expect(input.className).toMatch('ant-input-status-success')})})
})

匹配器

toBe :期待是否与匹配器中的值相等,相当于object.is ===

toMatch :匹配当前字符串中是否含有这个值,支持正则

toContain :用于检查数组或字符串是否包含特定项或子串

toBeInTheDocument :判断某个元素是否在文档中,即是否已被渲染到 DOM 上

toHaveProperty :用于检查对象是否具有特定属性,可以选择性地检查属性值

toEqual :是“相等”,不是“相同”,相当于==

toBeFalsy 和 toBeTruthy :检查一个值是否为假或真

toBeNull :专门用来检查一个值是否为 null

toBeDefined 和 toBeUndefined :这些断言用于检查变量是否已定义或未定义

toThrow :用于检查函数是否抛出错误

not:用于对断言取反

snapshot 快照

会在当前测试文件位于的文件夹下生成一个__snapshots__文件夹,该文件夹下会生成扩展名为 .snap 文件,文件会保存代码运行的结果(如渲染的组件树、数据结构等)。

toMatchSnapshot 方法:接受一个参数是快照名称,字符串类型。

expect(container).toMatchSnapshot('必填')

一定要是 container ,不能是 screen ,用 screen 不会保存 DOM 结构

优势
自动化比较:Jest 自动比较快照,减少了手动检查输出的需要。

简化复杂结构的测试:对于复杂的对象或大型UI组件,编写传统测试断言可能很困难。快照测试可以轻松捕获整个结构。

文档化变化:快照文件也可以作为代码行为的一种文档,让开发者和审阅者理解代码更改的影响。

快照更新:当代码发生更改,导致快照不再匹配时,可以使用 jest --updateSnapshot 命令或jest -u命令来更新快照。

测试用例覆盖率报告

会在主文件夹下生成一个名为 coverage 的文件夹,打开里面的 html 就可以看到各个文件的覆盖率,通常包含以下几种主要的覆盖率类型:

行覆盖率(Line Coverage):测量有多少行代码被测试用例执行过。如果一行代码在测试中至少被执行一次,那么这一行就被认为是覆盖了的。

函数覆盖率(Function Coverage):测量有多少个函数或方法被测试用例调用过。即使函数内的某些行没有被执行,只要函数被调用,它就被认为是覆盖了的。

分支覆盖率(Branch Coverage):测量代码中的每个if语句、循环、switch语句等的每个分支是否都被执行过。这是检查条件语句的完整性的重要指标。

语句覆盖率(Statement Coverage):测量有多少个独立语句被测试执行过。这与行覆盖率类似,但关注的是语句的执行。

React Testing Library

render

渲染 React 组件到一个虚拟的 DOM 环境中以便进行测试。

render 函数接受一个 React 组件作为参数,并返回一个包含多个属性和方法的对象,例如 container 和 debug 。 container 可以调用各类查询函数在渲染的组件中查找元素, debug 可以打印出 baseElement 的内部HTML,用于调试。

describe('测试输入框的校验规则', () => {it('输入正常', async () => {const Com = <Index />const container = render(Com)container.debug()})
})

screen

在使用 React Testing Library 进行测试时,通常会先用 render 函数渲染组件,然后用 screen 查询和操作元素。screen 对象可以在测试文件中全局访问,无需在每个测试中单独导入或创建。

describe('测试输入框的校验规则', () => {it('输入正常', async () => {render(<Index />)screen.debug()})
})

查询函数

React Testing Library 提供了一系列的查询函数,用于在 Jest 测试中找到 DOM 节点。

getBy…

getByText: 根据文本内容查找元素。

getByLabelText: 根据关联的 <label> 文本查找 <input>, <select>, 或 <textarea> 元素。

getByPlaceholderText: 根据占位符文本查找输入框。

getByAltText: 根据图片的 alt 属性文本查找图片元素。

getByTitle: 根据 title 属性查找元素。

getByRole: 根据 ARIA 角色查找元素。

getByTestId: 根据 data-testid 属性查找元素。

queryBy…

queryBy...函数的行为类似于 getBy... 函数,但当查询的元素不存在时,它们返回 null 而不是抛出错误。这对于断言某个元素不在页面上非常有用。

findBy…

findBy...函数是 getBy... 函数的异步版本。它们返回一个 Promise,适用于等待异步操作完成后元素出现在 DOM 中的情况。

…AllBy…, queryAllBy…, findAllBy…

这些函数的行为类似于 getBy..., queryBy..., 和 findBy...,但用于返回多个匹配的元素。如果没有找到匹配的元素,getAllBy...findAllBy... 会抛出错误,而 queryAllBy... 返回一个空数组。

总结:

getBy... 函数用于当确定元素存在时。如果元素不存在,测试将失败。
queryBy... 函数用于当元素可能不存在,需要处理这种情况时。
findBy... 函数用于处理异步逻辑,当需要等待元素出现时。
...AllBy... 函数用于处理有多个匹配元素的情况。

// findByText参数必须是完整的文本,如果是子字符串,需要加上{exact: false}
// findByText不管前缀是screen还是container都可以成功
describe('测试输入框的校验规则', () => {it('仅支持汉字、字母、数字和-_%.', async () => {const Com = <Index />const container = render(Com)const input = await screen.findByRole('textbox')await userEvent.type(input, '@')const messages = await container.findByText('溶剂名称仅支持汉字、字母、数字和-_%.')})
})
describe('测试输入框的校验规则', () => {it('仅支持汉字、字母、数字和-_%.', async () => {const Com = <Index />const container = render(Com)const input = await screen.findByRole('textbox')await userEvent.type(input, '@')const messages = await screen.findByText('仅支持汉字、字母、数字和-_%.', {exact: false})})
})

waitFor

用于处理异步操作和元素的异步更新。waitFor 常与异步查询函数(如 findBy…)结合使用,用于处理组件状态更新或数据加载。

describe('测试输入框的校验规则', () => {it('输入正常', async () => {const container = render(<Index />)screen.debug()const input = await screen.findByRole('textbox')await waitFor(() => {expect(screen.getByText('必填', { exact: false })).toBeInTheDocument()})})
})

fireEvent 和 userEvent

Jest 提供fireEventuserEvent模拟用户操作。

fireEvent:直接同步触发 DOM 事件。当调用 fireEvent 的任何方法时(如 fireEvent.click),它会立即生成对应的 DOM 事件,并同步地传递给目标元素。因此,fireEvent 方法调用后不会返回 Promise,也不涉及任何异步操作,所以通常不需要使用 await 关键字。

userEvent:旨在更贴近用户的实际操作,因此它经常涉及到一系列复杂的、可能是异步的事件。例如,当用户在输入框中输入文字时,这不仅仅是一个简单的同步操作。它包含了一系列的键盘和输入事件,这些事件可能会触发各种事件处理器,这些处理器本身可能是异步的。

1、fireEvent来自'@testing-library/react'userEvent来自@testing-library/user-event

2、fireEvent的清空 Input 输入框操作为fireEvent.change(input, {target: {value: ''}})userEvent的清空 Input 输入框操作为userEvent.type(input, '{backspace}')

3、fireEvent前不需要添加awaituserEvent需要。

总结:如果需要模拟简单的事件并需要完全控制这些事件的属性,fireEvent 是个好选择。而如果需要模拟更复杂或更接近真实用户行为的交互,userEvent 则更合适。

describe('测试输入框的校验规则', () => {it('仅支持汉字、字母、数字和-_%.', async () => {const Com = <Index />const container = render(Com)const input = await screen.findByRole('textbox')fireEvent.change(input, {target: {value: '@'}})})
})
describe('测试输入框的校验规则', () => {it('仅支持汉字、字母、数字和-_%.', async () => {const Com = <Index />const container = render(Com)const input = await screen.findByRole('textbox')await userEvent.type(input, '@')})
})

Jest 测试案例

测试 Input 输入框的校验规则

当前 Input 输入框的校验规则:

(1)必填

(2)限长100

(3)仅支持汉字、字母、数字和-_%.

(4)必须以数字、字母或汉字开头

const nameRules = ({label,max = 10,required = true,
}: {label: stringmax?: numberrequired?: boolean
}): Rule[] => [{ required, message: `${label}必填` },{ type: 'string', max, message: `${label}限长${max}` },{pattern: /^([a-zA-Z0-9\u4E00-\u9FA5_.%-])*$/g,message: `${label}仅支持汉字、字母、数字和-_%.`,},{pattern: /^([0-9|a-zA-Z0-9|\u4E00-\u9FA5])/g,message: `${label}以数字、字母或汉字开头`,},]

因被测试组件的复杂程度不同,测试同一个功能所用的 API 也不同

(1)被测试功能组件的简单版:

该组件只有基本的页面布局和nameRules校验规则

/* eslint-disable react-hooks/rules-of-hooks */
import { nameRules } from '@/utils/constants'
import { Form, Input } from 'antd'const myInput = () => {return (<Form><Form.Itemlabel="Username"name="username"// 校验规则rules={nameRules({label: '名称',required: true,})}><Input /></Form.Item></Form>)
}
export default myInput

在测试较简单的组件时,模拟用户操作可以使用fireEvent.change(),断言也无需包裹在waitFor中便可同步执行。

/* eslint-disable no-undef */
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import Index from './index'
import '@testing-library/jest-dom'describe('测试输入框的校验规则', () => {it('必填', async () => {// 渲染组件const Com = <Index />const container = render(Com)// findByRole不管前缀是screen还是container都可以成功const input = await screen.findByRole('textbox')// 在 input 输入框中输入1fireEvent.change(input, { target: { value: '1' } })// 清空 inputfireEvent.change(input, { target: { value: '' } })// findByText参数必须是完整的文本,如果是子字符串,需要加上{exact: false}expect(await container.findByText('必填', { exact: false })).toBeInTheDocument()})it('仅支持汉字、字母、数字和-_%.', async () => {const Com = <Index />const container = render(Com)const input = await screen.findByRole('textbox')fireEvent.change(input, { target: { value: '@' } })expect(await container.findByText('仅支持汉字、字母、数字和-_%.', { exact: false })).toBeInTheDocument()})it('以数字、字母或汉字开头', async () => {const Com = <Index />const container = render(Com)const input = await screen.findByRole('textbox')fireEvent.change(input, { target: { value: '-' } })expect(await container.findByText('以数字、字母或汉字开头', { exact: false })).toBeInTheDocument()})it('限长', async () => {const Com = <Index />const container = render(Com)const input = await screen.findByRole('textbox')fireEvent.change(input, { target: { value: 'a'.repeat(101) } })expect(await container.findByText('限长', { exact: false })).toBeInTheDocument()})it('输入正常', async () => {const Com = <Index />const container = render(Com)const input = await screen.findByRole('textbox')fireEvent.change(input, { target: { value: '1' } })await waitFor(() => {expect(input.className).toMatch('ant-input-status-success')})})
})

(2)被测试功能组件的复杂版:

该组件是个集合组件,功能比较复杂,被测试的输入框只是其中一小部分内容。

因为组件存在 fetch 接口的请求,但是 jest 测试不会运行真实的 fetch 接口,所以需要 mock 数据,在本组件中通过在catch中给定初始数据。

在复杂环境下render组件时,需要 mock 渲染组件所需的各项参数,在本组件中id值是直接给定一个存在的 id ,onCancel方法 mock 一个空函数,Dn初始化数据。

此时模拟用户操作须使用await userEvent.type(),断言外须包裹await waitFor(() => {})

/* eslint-disable no-undef */
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import ComplexIndex from './ComplexIndex'
import '@testing-library/jest-dom'
import userEvent from '@testing-library/user-event'describe('测试输入框的校验规则', () => {const onCancelMock = jest.fn()it('必填', async () => {// 渲染组件render(<ComplexIndexid="93e"onCancel={onCancelMock}Dn={{dn1: 1,dn2: '',}}/>)const input = await screen.findByRole('textbox')// 在 input 输入框中输入“正常输入”await userEvent.type(input, '1')// 清空 inputawait userEvent.type(input, '{backspace}')// 异步等待断言执行await waitFor(() => {expect(screen.getByText('必填', { exact: false })).toBeInTheDocument()})})it('正常输入', async () => {render(<ComplexIndexid="93e"onCancel={onCancelMock}Dn={{dn1: 1,dn2: '',}}/>)const input = await screen.findByRole('textbox')await userEvent.type(input, '正常输入')await waitFor(() => {expect(input.className).toMatch('ant-input-status-success')})})it('限长', async () => {render(<ComplexIndexid="93e"onCancel={onCancelMock}Dn={{dn1: 1,dn2: '',}}/>)const input = await screen.findByRole('textbox')await userEvent.type(input, 'a'.repeat(101))await waitFor(() => {expect(screen.getByText('限长', { exact: false })).toBeInTheDocument()})})it('仅支持汉字、字母、数字和-_%.', async () => {render(<ComplexIndexid="93e"onCancel={onCancelMock}Dn={{dn1: 1,dn2: '',}}/>)const input = await screen.findByRole('textbox')await userEvent.type(input, '@')await waitFor(() => {expect(screen.getByText('仅支持汉字、字母、数字和-_%.', { exact: false })).toBeInTheDocument()})})it('以数字、字母或汉字开头', async () => {render(<ComplexIndexid="93e"onCancel={onCancelMock}Dn={{dn1: 1,dn2: '',}}/>)const input = await screen.findByRole('textbox')await userEvent.type(input, '-')await waitFor(() => {expect(screen.getByText('以数字、字母或汉字开头', { exact: false })).toBeInTheDocument()})})
})

(3)获取原始 DOM 内容进行测试

Input 标签有aria-describedby属性,该属性的属性值是某个divid,该div下的div包含所有类型的报错字样。

/* eslint-disable no-undef */
import { fireEvent, render, screen } from '@testing-library/react'
import Index from './index'
import '@testing-library/jest-dom'
import userEvent from '@testing-library/user-event'describe('测试输入框的校验规则', () => {it('仅支持汉字、字母、数字和-_%.', async () => {// 渲染被测组件const Com = <Index />const container = render(Com)// 获取input元素const input = await screen.findByRole('textbox')// 在input输入框中输入@await userEvent.type(input, '@')// 获取input元素const inputEl = document.querySelector("input[type='text']")// 获取input元素的所有属性const attributes = inputEl!.attributeslet ariaDescribedby = ''for (let i = 0; i < attributes?.length; i++) {console.log(attributes[i].name, attributes[i].value)// 找到aria-describedby属性if (attributes[i].name === 'aria-describedby') {// 获取 aria-describedby 属性的值ariaDescribedby = attributes[i].value}}// div 的 id 值为 aria-describedby 属性的值const borderDiv = document.getElementById(ariaDescribedby)const childrenDiv = borderDiv?.querySelectorAll('div')childrenDiv?.forEach(div => {// 报错文本console.log(div.textContent)})})
})

Jest VSCode 插件

1、Jest

内置测试运行器,可以直接运行和调试 jest 测试,可以测试某个 describe 或者某个 describe 中的单个 it

相关文章:

(2.2w字)前端单元测试之Jest详解篇

Jest Jest 概述 Jest是一个领先的JavaScript测试框架&#xff0c;特别适用于React和Node.js环境。由Facebook开发&#xff0c;它以简单的配置、高效的性能和易用性而闻名。Jest支持多种类型的测试&#xff0c;包括单元测试、集成测试和快照测试&#xff0c;后者用于捕获组件或…...

【C++私房菜】面向对象中的多态

文章目录 一、多态二、对象的静态类型和动态类型三、虚函数和纯虚函数1、虚函数2、虚析构函数3、抽象基类和纯虚函数4、多态的原理 四、重载、覆盖(重写)、隐藏(重定义)的对比 一、多态 OOP的核心思想是多态性(polymorphism)。多态性这个词源自希腊语&#xff0c;其含义是“多…...

(done) 什么是特征值和特征向量?如何求特征值的特征向量 ?如何判断一个矩阵能否相似对角化?

什么是齐次方程&#xff1f; https://blog.csdn.net/shimly123456/article/details/136198159 行列式和是否有解的关系&#xff1f; https://blog.csdn.net/shimly123456/article/details/136198215 特征值和特征向量 参考视频&#xff1a;https://www.bilibili.com/video/BV…...

[rust] 11 所有权

文章目录 一 背景二 Stack 和 Heap2.1 Stack2.2 Heap2.3 性能区别2.4 所有权和堆栈 三 所有权原则3.1 变量作用域3.2 String 类型示例 四 变量绑定背后的数据交互4.1 所有权转移4.1.1 基本类型: 拷贝, 不转移所有权4.1.2 分配在 Heap 的类型: 转移所有权 4.2 Clone(深拷贝)4.3 …...

MySQL安装

文章目录 MYSQL安装一、下载二、解压三、配置1. 添加环境变量2. 初始化MySQL3. 注册MySQL服务4. 启动MySQL服务5. 修改默认账户密码 四、登录MySQL五、卸载MySQL MYSQL安装 一、下载 点开下面的链接&#xff1a;https://dev.mysql.com/downloads/mysql/ 点击Download 就可以下…...

AI时代显卡如何选择,B100、H200、L40S、A100、H100、V100 含架构技术和性能对比

AI时代显卡如何选择&#xff0c;B100、H200、L40S、A100、H100、V100 含架构技术和性能对比。 英伟达系列显卡大解析B100、H200、L40S、A100、A800、H100、H800、V100如何选择&#xff0c;含架构技术和性能对比带你解决疑惑。 近期&#xff0c;AIGC领域呈现出一片繁荣景象&a…...

R语言入门笔记2.5

数据预处理 R语言处理的数据多以数据框的形式出现。 预备操作 数据查看 > dim(x) [1] 16 3 #数据框有16行3列 > names(x) #查看数据框的变量名 [1] "X" "Z" "Y" > head(x,3) #查看前3行&#xff0c;若为-3则是查看后三行之…...

命令记录学习

1. 查看当前用户 cat /etc/passwd 添加test用户 useradd test -G root 查看test用户状态 id test 查看用户adaminstrator passwd -S adaminstrator 禁用用户adaminstrator passwd -l adaminstrator 密码策略设置文件地址 vi /etc/pam.d/system-auth 设…...

Python3 TCP 客户端

下面是一个简单的 Python TCP 客户端示例代码&#xff0c;用于与之前提到的 EchoServer 进行通信&#xff1a; import socketserver_address (localhost, 8888)# 创建 TCP 客户端套接字 client_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM)try:# 连接到服务器…...

图论(算法竞赛、蓝桥杯)--拓扑排序

1、B站视频链接&#xff1a;D01 拓扑排序_哔哩哔哩_bilibili #include <bits/stdc.h> using namespace std; const int N100010; int n,m,a,b; vector<int> e[N],tp; int din[N]; bool topsort(){queue<int> q;for(int i1;i<n;i){if(din[i]0)q.push(i);}…...

内网穿透(docker部署frp)

文章目录 内网穿透实现内网穿透的常见方法 frpfrp的实现原理frps服务端应用部署配置文件部署参数配置 frpc客户端部署 内网穿透 内网穿透是指在内部网络&#xff08;内网&#xff09;中实现穿透外网&#xff08;公网&#xff09;的通信。内网通常是指公司、组织或家庭等内部网…...

Java设计模式 | 简介

设计模式的重要性&#xff1a; 软件工程中&#xff0c;设计模式&#xff08;design pattern&#xff09;是对软件设计中普遍存在&#xff08;反复出现&#xff09;的各种问题&#xff0c;所提出的解决方案。 这个术语由埃里希 伽玛&#xff08;Erich Gamma&#xff09;等人在1…...

微信小程序video 点击自动全屏播放

//因为这个地址可能是图片也可能是视频 点击 图片可以预览&#xff0c;点击视频可放大全屏自动播放。 代码如下 <view v-else :class{contentImg: x.picture.length0} style"margin-top: 10px;"v-for"(x1, y1) in x.picture" :key"y"><…...

MySQL基础面试问题(一)

MySQL面试问题的标准回答&#xff1a; 什么是数据库范式&#xff1f;MySQL中常见的范式有哪些&#xff1f; 标准回答&#xff1a;数据库范式是一组规则&#xff0c;用于设计关系型数据库的结构&#xff0c;以减少数据冗余和提高数据的一致性。常见的数据库范式包括第一范式&…...

抖音爬虫批量视频提取功能介绍|抖音评论提取工具

抖音爬虫是指通过编程技术从抖音平台上获取视频数据的程序。在进行抖音爬虫时&#xff0c;需要注意遵守相关法律法规和平台规定&#xff0c;以确保数据的合法获取和使用。 一般来说&#xff0c;抖音爬虫可以实现以下功能之一&#xff1a;批量视频提取。这个功能可以用于自动化地…...

mac真的安装不了vmware吗 mac如何安装crossover crossover序列号从哪里买 购买正版渠道

有些用户可能想在mac上运行一些只能在windows上运行的软件&#xff0c;比如游戏、专业软件等。这时候&#xff0c;就需要用到虚拟机技术&#xff0c;也就是在mac上安装一个可以模拟其他操作系统的软件&#xff0c;比如vmware或者crossover。那么&#xff0c;mac真的安装不了vmw…...

C语言-指针详解速成

1.指针是什么 C语言指针是一种特殊的变量&#xff0c;用于存储内存地址。它可以指向其他变量或者其他数据结构&#xff0c;通过指针可以直接访问或修改存储在指定地址的值。指针可以帮助我们在程序中动态地分配和释放内存&#xff0c;以及进行复杂的数据操作。在C语言中&#…...

C# RabbitMQ使用--动态更新

在使用 RabbitMQ 的 C# 客户端库时&#xff0c;只需要在应用程序中引用 RabbitMQ.Client 包&#xff0c;而不需要单独安装 RabbitMQ 服务器。 RabbitMQ.Client 是一个用于在 C# 中与 RabbitMQ 服务器进行通信的客户端库。通过使用该客户端库&#xff0c;你可以在应用程序中创建…...

Unity资源加密解决方案

据统计&#xff0c;全球范围内超过50%的游戏均使用Unity创作而成&#xff0c;作为游戏开发市场第一大游戏引擎占有者&#xff0c;Unity已经全面覆盖到各个游戏平台。 全球游戏引擎市场占有率 由于体量庞大&#xff0c;Unity游戏已成为受游戏黑灰产攻击的重灾区&#xff0c;因游…...

使用 yarn 的时候,遇到 Error [ERR_REQUIRE_ESM]: require() of ES Module 怎么解决?

晚上回到家&#xff0c;我打开自己的项目&#xff0c;执行&#xff1a; cd HexoPress git pull --rebase yarn install yarn dev拉取在公司 push 的代码&#xff0c;然后更新依赖&#xff0c;最后开始今晚的开发时候&#xff0c;意外发生了&#xff0c;竟然报错了&#xff0c;…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...