新手也能看懂的前端单元测试框架:Vitest

 

单元测试的概念及作用

1.什么是单元测试?

单元测试是测试中的一个重要环节,它针对软件中的最小可测试单元进行验证,通常是指对代码中的单个函数、方法或模块进行测试。

单元测试旨在确定特定部分代码的行为是否符合预期,通过针对单元代码的各种输入情况进行测试,来验证代码的正确性、稳定性和可靠性。

2.为什么要做单元测试?

  • 2.1 确保代码质量和可靠性:单元测试可以帮助开发人员发现和修复代码中的错误和缺陷。通过编写针对每个单独的函数或组件的测试用例,可以验证其行为是否符合预期,从而增强代码质量和可靠性。

  • 2.2 提高代码可维护性: 单元测试可以作为文档和说明来帮助其他开发人员了解代码的预期行为。通过编写清晰、有目的性的测试用例,可以帮助开发团队更好地理解和维护代码。

  • 2.3 快速反馈和迭代: 单元测试使得代码的迭代和快速反馈变得更加容易。通过自动运行测试用例,开发人员在修改代码后可以快速获得有关是否引入新错误或破坏现有功能的反馈。

  • 2.4 节省时间和资源: 尽管编写和维护单元测试需要一些额外的工作量,但它可以节省大量的时间和资源。通过快速检测和修复代码中的错误,可以避免在后期发现问题并进行繁琐的调试和修复。

    此外,当代码库变得越来越大和复杂时,拥有一套稳健的单元测试可以节省大量的回归测试时间。

3.前端代码单元测试面临的挑战与问题

  • 3.1 难以测试 DOM 操作: 前端开发中最常见的任务之一就是操作 DOM,但由于浏览器环境的限制,DOM 操作很难通过自动化测试来模拟。这意味着要测试 DOM 操作通常需要手动测试或使用可视化测试工具。

  • 3.2 异步操作的测试: 在前端开发中,异步代码执行是比较常见的。但是,异步测试需要在数据返回之前等待一段时间。

  • 3.3 测试用例覆盖率的管理: 在编写测试用例时,需要考虑完整和准确地覆盖所有代码路径。但是,测试用例的数量和管理可以是一个挑战,并且可能需要一些额外的工具来帮助管理测试用例的覆盖率。

  • 3.4 特定 DOM 事件和浏览器环境的测试: 在某些情况下,需要通过特定的 DOM 事件和浏览器环境对代码进行测试。这可以通过模拟特定的事件和使用虚拟浏览器环境来完成。

前端单元测试工具以及测试规范

1.测试工具

以下是一些流行的前端单元测试工具:

  • 1.1 Jest:Jest 是一个 Facebook 公司开发的流行的 JavaScript 测试框架。它提供了自动化测试、模拟和覆盖率报告等功能。Jest 的主要特点是易于使用速度快自动运行测试用例和提供详细报告。

  • 1.2 Mocha:Mocha 是一个流行的 JavaScript 测试框架,可以用于编写前端和后端测试用例。它提供不同的测试运行器、测试框架、覆盖率报告等工具。Mocha 可以与其他库(如 ChaiSinon 等)结合使用,以提供更好的测试功能。

  • 1.3 Enzyme:Enzyme 是一个 React 组件测试工具,它提供了一个简单的 API 来模拟 React 组件的行为。Enzyme 可以帮助开发人员测试组件的渲染和逻辑,以确保其正确性。它还提供了丰富的匹配器和渲染引擎,以进行功能和性能测试。

实际项目中测试框架和工具选择:

  • 测试基础框架:Vitest ,它是基于vite驱动,如果项目中使用了vite,它是最好的选择

  • DOM 环境jsdomhappy-dom

React项目:

  • @testing-library/react:作为 React DOM 和 UI 组件

  • @testing-library/jest-dom用于扩展Vitestexpect方法

Vue项目

  • vue-router-mock:模拟 Vue 3应用程序中的路由交互

  • @vitejs/plugin-vue 是一个 Vite 插件,它可以让 Vite 可以解析 .vue 文件,对于 JSX/TSX 支持,还需要@vitejs/plugin-vue-jsx

  • @vue/test-utils:Vue 3的组件测试工具

2.测试规范

(1) 命名约定it or test?

  • 1、it是 BDD(行为驱动开发)风格中常用的命名约定。它强调描述被测试行为的自然语言描述,以便更好地阐述测试的用例。

  • 2、test是传统的命名约定,被广泛使用在各种单元测试框架中。它更加直接和简洁,通常以测试的目标作为开头,然后描述被测试的函数或特性。

无论使用it还是test作为测试函数的命名约定,最重要的是保持一致性和可读性。根据你的团队或项目的偏好,选择一个适合的命名约定并始终如一地使用它。

(2) 判断相等toBe or toEqual?

  • 1、toBe它使用===检查严格的平等,通常用于比较基础类型。

  • 2、toEqual用于检查两个对象具有相同的值。这个匹配器递归地检查所有字段的相等性,而不是检查对象身份 - 这也被称为“深度平等”。

使用toBe进行比较时要注意,它比较的是两个对象的引用,而不是对象的属性是否相同。

(3) 测试文件写在哪?

  • 1、把测试文件统一写在 src/test/,这样保持项目和测试代码分离,保持工程目录整洁。

  • 2、和组件写在同一级目录,即src/components/下,xx.jsxxx.test.jsx, 这样对开发人员友好,组件与测试一起更方便维护。

(4) 测试用例注意事项

  • 1、清晰的目的和描述:测试用例应该具有清晰的目的和描述,以便于理解和维护。用一个简洁但有意义的名称来描述该测试用例的功能或行为。

  • 2、单一功能和场景:每个测试用例应该只关注一个功能或一个特定的场景。这有助于准确地定位和修复问题。

  • 3、确保环境一致性:对于每个测试用例,提供必要的前提条件,确保测试环境的一致性。

  • 4、测试目标简单、完整:尽量把业务代码的函数的功能单一化,简单化。如果一个函数的功能包含了十几个功能数十个功能,那应该对该函数进行拆分,从而更加有利于测试的进行。

使用Vitest测试React项目

1.安装相关工具

pnpm i -D vitest js-dom @testing-library/react

Vitest 1.0 需要 Vite >=v5.0.0 和 Node >=v18.0

2.配置vitest

Vitest 的主要优势之一是它与 Vite 的统一配置。如果存在,vitest 将读取你的根目录 vite.config.ts 以匹配插件并设置为你的 Vite 应用程序。

如果你已经在使用 Vite,请在 Vite配置中添加 test 属性。你还需要使用 三斜杠指令 在你的配置文件的顶部引用。

vite.config.ts

 
  1. /// <reference types="vitest" />

  2. import { defineConfig } from 'vite'

  3. export default defineConfig({

  4. test: {

  5. globals: true,

  6. environment: 'jsdom',

  7. },

  8. })

  • globals: 默认情况下,vitest 不显式提供全局 API。如果你更倾向于使用类似 jest 中的全局 API,可以将 --globals 选项传递给 CLI 或在配置中添加 globals: true

  • environment: Vitest中的默认测试环境是一个 Node.js 环境。如果你正在构建 Web 端应用程序,你可以使用 jsdom 或 happy-dom 这种类似浏览器(browser-like)的环境来替代 Node.js

可以参阅 配置索引(https://cn.vitest.dev/config/) 中的配置选项列表

3.方法测试

测试独立的工具函数,例如测试斐波那契数列:

@param方法接受参数 num

@return返回值为斐波那契数列中第 n 个数字fibonacci.ts

 
  1. export function fibonacci(num: number): number {

  2. if (num <= 1) {

  3. return num;

  4. }

  5. return fibonacci(num - 1) + fibonacci(num - 2);

  6. }

fibonacci.test.ts

 
  1. import { describe, it, expect } from 'vitest';

  2. import { fibonacci } from '@/utils/fibonacci/fibonacci.ts';

  3. describe('fibonacci', () => {

  4. it('should return 0 when num is 0', () => {

  5. expect(fibonacci(0)).toEqual(0);

  6. });

  7. it('should return 1 when num is 1', () => {

  8. expect(fibonacci(1)).toEqual(1);

  9. });

  10. it('should return 1 when num is 2', () => {

  11. expect(fibonacci(2)).toEqual(1);

  12. });

  13. it('should return 2 when num is 3', () => {

  14. expect(fibonacci(3)).toEqual(2);

  15. });

  16. it('should return 3 when num is 4', () => {

  17. expect(fibonacci(4)).toEqual(3);

  18. });

  19. });

当编写测试用例来测试独立的方法或函数时,应满足以下要求👇:

  • 1、边界条件测试:测试应该覆盖方法或函数的所有边界条件。这包括输入的最小值、最大值、边界情况和异常情况。

  • 2、异常处理测试:测试应该包括错误情况和异常处理,以确保方法或函数能够正确地处理这些情况,而不会导致系统崩溃或出现错误。

4.快照测试

快照测试是一种用于比较当前渲染结果与预期快照的自动化测试技术。

适用场景:测试一个纯渲染的组件,UI渲染一次后不再发生改变。这种场景下就不需要再耗费精力去单测,而是采用低成本的快照测试。

Result.tsx

 
  1. import type { FC } from 'react';

  2. type Student = {

  3. id?: number;

  4. name?: string;

  5. };

  6. interface PropsType {

  7. stus: Student[];

  8. }

  9. const Results: FC<PropsType> = ({ stus }) => {

  10. return (

  11. <div className="search">

  12. {!stus.length ? (

  13. <h1>No Data</h1>

  14. ) : (

  15. stus.map((stu: Student) => {

  16. return (

  17. <div key={stu.id}>

  18. <div className="info">

  19. <h1>{stu.name}</h1>

  20. </div>

  21. </div>

  22. );

  23. })

  24. )}

  25. </div>

  26. );

  27. };

  28. export default Results;

Results.test.tsx​​​​​​​

 
  1. import { render } from '@testing-library/react';

  2. import { describe, expect, it } from 'vitest';

  3. import Results from './Results.tsx';

  4. describe('Results', () => {

  5. // 快照测试,会在当前目录下生成__snapshots__文件夹和快照文件

  6. it('should renders correctly with no stus', () => {

  7. const { asFragment } = render(<Results stus={[]} />);

  8. // 渲染快照结果是否与存档快照一致

  9. expect(asFragment()).toMatchSnapshot();

  10. });

  11. it('should renders correctly with some stus', () => {

  12. const stus = [

  13. {

  14. id: 1,

  15. name: 'Luna'

  16. },

  17. ];

  18. const { asFragment } = render(<Results stus={stus} />);

  19. // 渲染快照结果是否与存档快照一致

  20. expect(asFragment()).toMatchSnapshot();

  21. });

  22. });

在第一次执行完测试用例后,当前目录会生成以下文件:【图片】

后续的每次测试会将最新结果和这里保存的结果进行对比,如果一致,则代表测试通过,反之,则不然。

5.组件测试

日常开发中,我们接触最多的就是组件,越来越多的框架推荐页面组件化,组件也必然是单元测试的目标对象之一。

首先应该知道对于组件,应该测试哪些内容:

  • Component Data:组件静态数据

  • Component Props:组件动态数据

  • User Interaction:用户交互,例如单击

  • LifeCycle Methods:生命周期逻辑

  • Store:组件状态值

  • Route Params:路由参数

  • 输出的DOM

  • 外部调用的函数Hook

  • 对子组件的改变

5.1组件DOM测试

组件根据不同的props输入,组件会呈现不同的DOM结构,我们可以通过@testing-library/react 库提供的render API,结合jsdom(在Node环境中提供对 web 标准的模拟实现)来完成DOM测试。

Pet.tsx​​​​​​​

 
  1. import type { FC } from 'react';

  2. interface PropsType {

  3. id?: number;

  4. name?: string;

  5. animal?: string;

  6. breed?: string;

  7. images?: string[];

  8. location?: string;

  9. }

  10. const Pet: FC<PropsType> = (props) => {

  11. const { name, animal, breed, images, location, id } = props;

  12. let hero = 'http://pets-images.dev-apis.com/pets/0.jpg';

  13. if (images?.length) {

  14. hero = images[0];

  15. }

  16. return (

  17. <div className="pet">

  18. <div className="image-container">

  19. <img data-testid="thumbnail" src={hero} alt={name} />

  20. </div>

  21. <div className="info">

  22. <h1>{name}</h1>

  23. <h2>{`${animal} — ${breed} — ${location}`}</h2>

  24. </div>

  25. </Link>

  26. );

  27. };

  28. export default Pet;

Pet.test.tsx​​​​​​​

  1. import { render } from '@testing-library/react';

  2. import { StaticRouter } from 'react-router-dom/server';

  3. import { expect, test } from 'vitest';

  4. import Pet from './Pet.tsx';

  5. test('displays a default thumbnail', async () => {

  6. // 渲染组件

  7. const pet = render(<Pet />);

  8. // 异步等待获取指定的DOM元素

  9. const petThumbnail = (await pet.findByTestId(

  10. 'thumbnail'

  11. )) as HTMLImageElement;

  12. // 断言0.jpg包含在src的属性值中

  13. expect(petThumbnail.src).toContain('0.jpg');

  14. // 卸载组件

  15. pet.unmount();

  16. });

有很多API可以断言一个元素是否存在,例如toBeInTheDocument,详细用法请查阅官方文档。

expect(testDom).toBeInTheDocument();

5.2交互测试

上面测试了组件能够按预期渲染,单一个这样的用例是远远不够的,我们还需要模拟用户交互行为,来测试组件是否符合预期,例如常见的点击、拖拽等。

Carousel.tsx​​​​​​​

  1. import type { FC, MouseEvent } from 'react';

  2. import { useState } from 'react';

  3. interface PropsType {

  4. images?: string[];

  5. }

  6. const Carousel: FC<PropsType> = (props) => {

  7. const { images = ['http://pets-images.dev-apis.com/pets/0.jpg'] } = props;

  8. const [active, setActive] = useState<number>(0);

  9. const handleIndexClick = (event: MouseEvent) => {

  10. const { index = 0 } = (event.target as HTMLImageElement).dataset;

  11. setActive(+index);

  12. };

  13. return (

  14. <div className="carousel">

  15. <img data-testid="hero" src={images[active]} alt="animal" />

  16. <div className="carousel-smaller">

  17. {images.map((photo, index) => (

  18. <img

  19. key={photo}

  20. src={photo}

  21. className={index === active ? 'active' : ''}

  22. alt="animal thumbnail"

  23. onClick={(e) => handleIndexClick(e)}

  24. data-index={index}

  25. data-testid={`thumbnail${index}`}

  26. />

  27. ))}

  28. </div>

  29. </div>

  30. );

  31. };

  32. export default Carousel;

Carousel.test.tsx​​​​​​​

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

  2. import { expect, test } from 'vitest';

  3. import Carousel from './Carousel.tsx';

  4. test('lets users click on thumbnails to make them the hero', async () => {

  5. const images = ['0.jpg', '1.jpg', '2.jpg', '3.jpg'];

  6. const carousel = render(<Carousel images={images} />);

  7. const hero = (await carousel.findByTestId('hero')) as HTMLImageElement;

  8. expect(hero.src).toContain(images[0]);

  9. for (let i = 0; i < images.length; i++) {

  10. const image = images[i];

  11. const thumb = await carousel.findByTestId(`thumbnail${i}`);

  12. act(() => {

  13. // 模拟 click 用户事件

  14. fireEvent.click(thumb);

  15. });

  16. expect(hero.src).toContain(image);

  17. expect(Array.from(thumb.classList)).toContain('active');

  18. }

  19. });

6.React Hook 测试

这里的Hook是指业务中自定义封装的Hook,我们知道Hook只能在函数组件中调用,那如何来做单元测试呢?RTL中提供了renderHook ,专门用来调用 Hook

useSearch.ts​​​​​​​

 
  1. import { useState, useMemo } from 'react';

  2. /**

  3. * useSearch 数据过滤

  4. * @param items 初始数组

  5. * @return

  6. * searchTerm 搜索词

  7. * setSearchTerm 更新搜索词方法

  8. * filteredItems 过滤后的数据

  9. */

  10. export const useSearch = (items: any[]) => {

  11. const [searchTerm, setSearchTerm] = useState('');

  12. const filteredItems = useMemo(() => {

  13. return items.filter((movie) =>

  14. movie.title.toLowerCase().includes(searchTerm.toLowerCase())

  15. );

  16. }, [items, searchTerm]);

  17. return {

  18. searchTerm,

  19. setSearchTerm,

  20. filteredItems,

  21. };

  22. };

useSearch.test.ts​​​​​​​

  1. import { act, renderHook } from '@testing-library/react';

  2. import { describe, expect, it } from 'vitest';

  3. import { useSearch } from '@/hooks/__test__/useSearch.ts';

  4. describe('useSearch hook', () => {

  5. // 测试返回默认搜索项 和 原始项目列表

  6. it('should return a default search term and original items', () => {

  7. const items = [{ title: 'Star Wars' }];

  8. // renderHook 模拟hook执行环境

  9. const { result } = renderHook(() => useSearch(items));

  10. // result.current 为useSearch hook的返回值

  11. expect(result.current.searchTerm).toBe('');

  12. expect(result.current.filteredItems).toEqual(items);

  13. });

  14. // 测试设置查询条件是否生效

  15. it('should return a filtered list of items', () => {

  16. const items = [{ title: 'Star Wars' }, { title: 'Starship Troopers' }];

  17. const { result } = renderHook(() => useSearch(items));

  18. // 反应,所有的渲染和触发的事件都包装在 act 中。它负责在调用之后刷新所有效果并重新渲染。

  19. act(() => {

  20. result.current.setSearchTerm('Wars');

  21. });

  22. expect(result.current.searchTerm).toBe('Wars');

  23. expect(result.current.filteredItems.length).toBe(1);

  24. expect(result.current.filteredItems).toEqual([{ title: 'Star Wars' }]);

  25. });

  26. });

7.异步、Mock测试​​​​​​​

7.1使用waitFor,异步等待接口返回

前端很多数据都是通过接口返回,页面需要等待接口返回后才能渲染,因此单元测试中的断言也需要等待,使用waitFor可以实现。

useMovies.ts​​​​​​​

  1. export const useMovies = ():{ movies: Movie[], isLoading: boolean, error: any } => {

  2. const [movies, setMovies] = useState([]);

  3. const fetchMovies = async () => {

  4. try {

  5. setIsLoading(true);

  6. const response = await fetch("https://swapi.dev/api/films");

  7. if (!response.ok) {

  8. throw new Error("Failed to fetch movies");

  9. }

  10. const data = await response.json();

  11. setMovies(data.results);

  12. } catch (err) {

  13. //do something

  14. } finally {

  15. //do something

  16. }

  17. };

  18. useEffect(() => {

  19. fetchMovies();

  20. }, []);

  21. return { movies }

  22. }

useMovies.test.ts​​​​​​​

  1. import { renderHook, waitFor } from '@testing-library/react';

  2. import { describe, expect, it } from 'vitest';

  3. import { useMovies } from '@/hooks/__test__/useMovies.ts';

  4. describe('useMovies hook', () => {

  5. //...

  6. it('should setTimeout movies', async () => {

  7. const { result } = renderHook(() => useMovies());

  8. // 在达到超时值之前,waitFor 可能会多次运行回调。请注意,调用的数量受到超时和间隔选项的限制

  9. await waitFor(() => {

  10. expect(result.current.isLoading).toBe(true);

  11. expect(result.current.movies).toEqual([{ title: 'Star Wars' }]);

  12. expect(result.current.error).toBe(null);

  13. });

  14. });

  15. });

waitFor的第二个参数是一个配置对象,可以配置超时时间,超过配置的上限后,测试为不通过.​​​​​​​

  1. // 默认间隔为50毫秒,超时时间是1000ms。第二个参数可以配置间隔和超时时间

  2. await waitFor(

  3. () => {

  4. // ...

  5. },

  6. {

  7. timeout: 1000,

  8. }

  9. );

7.2使用spyOn拦截请求方法,自定义mock

第一种方法是真实向后端发送了请求,在实际运用中可能不太合适。我们可以选择spyOn来拦截fetch,自己mock接口返回值,更加符合测试场景。​​​​​​​

  1. import { renderHook, waitFor } from '@testing-library/react';

  2. import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';

  3. import { useMovies } from '@/hooks/__test__/useMovies.ts';

  4. describe('useMovies hook', () => {

  5. // 通过vi.spyOn方法,我们可以在不触发真正的 API 调用的情况下运行测试,从而减少由于外部因素导致测试失败的机会。

  6. // 监视该global.fetch方法并模拟其实现以返回虚假响应

  7. const fetchSpy = vi.spyOn(global, 'fetch');

  8. // 注册一个回调函数,在开始运行当前上下文中的所有测试之前调用一次

  9. beforeAll(() => {

  10. const mockResolveValue = {

  11. ok: true,

  12. data: [{ title: 'Star Wars' }],

  13. };

  14. // 接受一个值,该值将在调用 mock 函数时返回

  15. fetchSpy.mockReturnValue(mockResolveValue as any);

  16. });

  17. // 测试 fetch异步获取数据

  18. it('should fetch movies', async () => {

  19. const { result } = renderHook(() => useMovies());

  20. await waitFor(() => {

  21. expect(result.current.isLoading).toBe(true);

  22. expect(result.current.movies).toEqual([{ title: 'Star Wars' }]);

  23. expect(result.current.error).toBe(null);

  24. });

  25. });

  26. // 注册一个回调函数,以便在当前上下文中所有测试运行完毕后调用一次。

  27. afterAll(() => {

  28. // 将内部实现还原为原始函数

  29. // 还可以在 beforeEach 或 afterEach 中使用 mockClear()in方法来确保我们的测试完全隔离

  30. fetchSpy.mockRestore();

  31. });

  32. });

通过调用vi.spyOn(global, 'fetch'),拿到代理方法,再调用mockReturnValue设置mock值,以此来模拟接口返回,这样更方便去断言。

由于我们模拟了fetch方法的返回值,因此需要在测试完成后使用mockRestore恢复其原始实现,还可以使用该mockClear()方法清除所有mock的信息

7.3测试生命周期

  • beforeAll:在当前文件的正式开始测试前执行一次,适合做一些每次 test 前都要做的初始化操作,比如数据库的清空以及初始化

  • beforeEach:在当前文件的每个 test 执行前都调用一次。

  • afterAll:在当前文件所有测试结束后执行一次,适合做一些收尾工作,比如将mock清除。

  • afterEach:在当前文件的每个 test 执行完后都调用一次。

结尾

这篇文章从单元测试的重要性测试工具测试实践三个方面,带大家入门前端单元测试。

相信大家认真学完后都能有收获!

 

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

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

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【谷粒商城】01-环境准备

1.下载和安装VirtualBox 地址&#xff1a;https://www.virtualbox.org/wiki/Downloads 傻瓜式安装VirtualBox 2.下载和安装Vagrant官方镜像 地址&#xff1a;https://app.vagrantup.com/boxes/search 傻瓜式安装 验证是否安装成功 打开CMD,输入vagrant命令&#xff0c;是否…

Linux的常用指令 和 基础知识穿插巩固(巩固知识必看)

目录 前言 ls ls 扩展知识 ls -l ls -a ls -al cd cd 目录名 cd .. cd ~ cd - pwd 扩展知识 路径 / cp [选项] “源文件名” “目标文件名” mv [选项] “源文件名” “目标文件名” rm 作用 用法 ./"可执行程序名" mkdir rmdir touch m…

单位个人怎样向报社的报纸投稿?

作为一名单位的信息宣传员,我肩负着每月定期在媒体上投稿发表文章的重任。然而,在投稿的道路上,我经历了不少波折和挫折。 一开始,我天真地以为只要将稿件发送到报社的投稿邮箱,就能轻松完成任务。然而,现实却远比我想象的复杂。邮箱投稿的竞争异常激烈,编辑们会在众多稿件中挑…

什么是直接内存(NIO)

直接内存不受 JVM 内存回收管理&#xff0c;是虚拟机的系统内存&#xff0c;常见于 NIO 操作时&#xff0c;用于数据 缓冲区&#xff0c;分配回收成本较高&#xff0c;但读写性能高&#xff0c;不受 JVM 内存回收管理。 举例 当上传一个较大文件&#xff08;200M&#xff09;…

【传知代码】VRT: 关于视频修复的模型(论文复现)

前言&#xff1a;随着数字媒体技术的普及&#xff0c;制作和传播视频内容变得日益普遍。但是&#xff0c;视频中由于多种因素&#xff0c;例如传输、存储和录制设备等&#xff0c;经常出现质量上的问题&#xff0c;如图像模糊、噪声干扰和低清晰度等。这类问题对用户的体验和观…

【Ubuntu20.04安装java-8-openjdk】

1 下载 官网下载链接&#xff1a; https://www.oracle.com/java/technologies/downloads/#java8 下载 最后一行 jdk-8u411-linux-x64.tar.gz&#xff0c;并解压&#xff1a; tar -zxvf jdk-8u411-linux-x64.tar.gz2 环境配置 1、打开~/.bashrc文件 sudo gedit ~/.bashrc2、…

【解决】:git clone项目报错fatal: fetch-pack: invalid index-pack output

象&#xff1a;之前一直使用gitee将个人学习和工作相关记录上传到个人gitee仓库&#xff0c;一直没出现过问题。直到有一天换电脑重新拉取代码发现出了问题&#xff0c;具体如下图&#xff1a; 原因分析&#xff1a; 经过查询发现主要原因是因为git clone的远程仓库的项目过大…

NVM安装及VUE创建项目的N种方式

VUE 参考官网&#xff1a;https://cli.vuejs.org/zh/guide/ 目录 NVM安装 1.卸载node.js 2.安装nvm ​编辑​ 3.配置 4.使用nvm安装node.js 5.nvm常用命令 创建VUE项目 1.使用vue init 创建vue2&#xff08;不推荐&#xff09; 2.使用vue create创建vue2和3&#xff…

Docker安装Mosquitto

在物联网项目中&#xff0c;我们经常用到MQTT协议&#xff0c;用MQTT协议做交互就需要部署一个MQTT服务&#xff0c;而mosquitto是一个常用的MQTT应用服务&#xff0c; Mosquitto是一个实现了消息推送协议MQTT v3.1的开源消息代理软件。MQTT&#xff08;Message Queuing Teleme…

knife4j案例

1.导入 <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId> </dependency>2.在配置类中加入 knife4j 相关配置并设置静态资源映射&#xff08;否则接口文档页面无法访问&#xff…

大模型LLM 结合联网搜索增强isou

参考&#xff1a; https://github.com/yokingma/search_with_ai 在线使用网址&#xff1a; https://isou.chat/ 安装github下载&#xff0c;运行docker compose 如果一直报下面错误&#xff1a; 解决方法https://github.com/yokingma/search_with_ai/pull/7 默认打开&a…

【PG数据库】PostgreSQL 日志归档详细操作流程

1.1 日志归档的目的 pg数据库日志归档是将PostgreSQL数据库的日志文件进行归档的过程。 归档的主要目的是为了保留历史数据&#xff0c;确保数据的一致性和完整性&#xff0c;同时为数据恢复提供必要的支持。 pg数据库日志归档的目的包括&#xff1a; 1.数据恢复&#xff1…

[链表专题]力扣141, 142

1. 力扣141 : 环形链表 题 : 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾…

洛谷P1364 医院设置

P1364 医院设置 题目描述 设有一棵二叉树&#xff0c;如图&#xff1a; 其中&#xff0c;圈中的数字表示结点中居民的人口。圈边上数字表示结点编号&#xff0c;现在要求在某个结点上建立一个医院&#xff0c;使所有居民所走的路程之和为最小&#xff0c;同时约定&#xff0c…

20240511每日运维----聊聊nignx改配置所有的nginx改完unknow

1、改配置所有的nginx改完unknow src/core/nginx.h src/http/ngx_http_header_filter_module.c src/http/ngx_http_special_response.c src/http/v2/ngx_http_v2_filter_module.c 2、make 3、去objs里面把nginx文件替换过去sbin/nginx

从JSON数据到Pandas DataFrame:如何解析出所需字段

目录 一、引言 二、JSON数据的基本结构 三、使用Pandas从JSON数据中读取数据 四、从DataFrame中解析出所需字段 解析对象字段 解析嵌套对象字段 解析数组字段 五、案例与代码示例 六、总结 一、引言 在数据分析和处理的日常工作中&#xff0c;我们经常需要从各种…

Python悬置动刚度模拟及复数绘制

Python悬置动刚度模拟及复数绘制 1、复数绘制极坐标图2、动刚度的计算公式3、悬置动刚度的影响因素4、 AVL Excite 悬置动刚度的模拟 1、复数绘制极坐标图 # _*_ coding:UTF-8 _*_import matplotlib.pyplot as plt import numpy as np# 定义复数数组 complexNums [1.5 1.2j,…

参考文献自检指南

参考文献作为论文的最后组成部分&#xff0c;可能不是加分项&#xff0c;但是做不好的话绝对会被吐槽&#xff0c;而且是个要命的减分项。因此要做好检查&#xff0c;以下是一些可以遵循的规范。&#xff08;如有疏漏&#xff0c;欢迎指出&#xff09; .bib文件 1.字段的选…

战网国际服下载教程 暴雪战网客户端一键下载安装教程分享

战网国际服务平台&#xff0c;又名Battle.net环球版&#xff0c;是暴雪娱乐操作的跨国界游戏交流平台&#xff0c;它消除了地域的隔阂&#xff0c;向全球范围内的游戏爱好者提供服务。与仅服务于特定地区的版本不同&#xff0c;国际版赋予了玩家自由穿梭于暴雪众多标志性游戏的…

解决ubuntu无法上网问题

发现是网络配置成了Manual手动模式&#xff0c;现在都改成自动分配DHCP模式 打开后&#xff0c;尝试上网还是不行&#xff0c;ifconfig查看ip地址还是老地址&#xff0c;怀疑更改没生效&#xff0c;于是重启试试。 重启后&#xff0c;ip地址变了&#xff0c;可以打开网页了 …