网站交给别人做安全吗wordpress 页面和分类目录
网站交给别人做安全吗,wordpress 页面和分类目录,网站公告栏怎么做,关于网站建设心得体会单元测试的概念及作用
1.什么是单元测试#xff1f;
单元测试是测试中的一个重要环节#xff0c;它针对软件中的最小可测试单元进行验证#xff0c;通常是指对代码中的单个函数、方法或模块进行测试。
单元测试旨在确定特定部分代码的行为是否符合预期#xff0c;通过针…单元测试的概念及作用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 JestJest是一个Facebook公司开发的流行的JavaScript测试框架。它提供了自动化测试、模拟和覆盖率报告等功能。Jest的主要特点是易于使用、速度快、自动运行测试用例和提供详细报告。1.2 MochaMocha是一个流行的JavaScript测试框架可以用于编写前端和后端测试用例。它提供不同的测试运行器、测试框架、覆盖率报告等工具。Mocha可以与其他库如Chai、Sinon等结合使用以提供更好的测试功能。1.3 EnzymeEnzyme是一个React组件测试工具它提供了一个简单的API来模拟React组件的行为。Enzyme可以帮助开发人员测试组件的渲染和逻辑以确保其正确性。它还提供了丰富的匹配器和渲染引擎以进行功能和性能测试。实际项目中测试框架和工具选择测试基础框架Vitest它是基于vite驱动如果项目中使用了vite它是最好的选择DOM 环境jsdom、happy-domReact项目testing-library/react作为React DOM和UI组件testing-library/jest-dom用于扩展Vitest的expect方法Vue项目vue-router-mock模拟Vue3应用程序中的路由交互vitejs/plugin-vue是一个Vite插件它可以让Vite可以解析.vue文件对于JSX/TSX支持还需要vitejs/plugin-vue-jsxvue/test-utilsVue3的组件测试工具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.jsx、xx.test.jsx, 这样对开发人员友好组件与测试一起更方便维护。(4) 测试用例注意事项1、清晰的目的和描述测试用例应该具有清晰的目的和描述以便于理解和维护。用一个简洁但有意义的名称来描述该测试用例的功能或行为。2、单一功能和场景每个测试用例应该只关注一个功能或一个特定的场景。这有助于准确地定位和修复问题。3、确保环境一致性对于每个测试用例提供必要的前提条件确保测试环境的一致性。4、测试目标简单、完整尽量把业务代码的函数的功能单一化简单化。如果一个函数的功能包含了十几个功能数十个功能那应该对该函数进行拆分从而更加有利于测试的进行。使用Vitest测试React项目1.安装相关工具pnpm i -D vitest js-dom testing-library/reactVitest 1.0需要Vite v5.0.0和Node v18.02.配置vitestVitest的主要优势之一是它与Vite的统一配置。如果存在vitest将读取你的根目录vite.config.ts以匹配插件并设置为你的Vite应用程序。如果你已经在使用Vite请在Vite配置中添加test属性。你还需要使用 三斜杠指令 在你的配置文件的顶部引用。vite.config.ts/// reference typesvitest /import { defineConfig } from viteexport default defineConfig({test: {globals: true,environment: jsdom,},})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方法接受参数numreturn返回值为斐波那契数列中第 n 个数字fibonacci.tsexport function fibonacci(num: number): number {if (num 1) {return num;}return fibonacci(num - 1) fibonacci(num - 2);}fibonacci.test.tsimport { describe, it, expect } from vitest;import { fibonacci } from /utils/fibonacci/fibonacci.ts;describe(fibonacci, () {it(should return 0 when num is 0, () {expect(fibonacci(0)).toEqual(0);});it(should return 1 when num is 1, () {expect(fibonacci(1)).toEqual(1);});it(should return 1 when num is 2, () {expect(fibonacci(2)).toEqual(1);});it(should return 2 when num is 3, () {expect(fibonacci(3)).toEqual(2);});it(should return 3 when num is 4, () {expect(fibonacci(4)).toEqual(3);});});当编写测试用例来测试独立的方法或函数时应满足以下要求1、边界条件测试测试应该覆盖方法或函数的所有边界条件。这包括输入的最小值、最大值、边界情况和异常情况。2、异常处理测试测试应该包括错误情况和异常处理以确保方法或函数能够正确地处理这些情况而不会导致系统崩溃或出现错误。4.快照测试快照测试是一种用于比较当前渲染结果与预期快照的自动化测试技术。适用场景测试一个纯渲染的组件UI渲染一次后不再发生改变。这种场景下就不需要再耗费精力去单测而是采用低成本的快照测试。Result.tsximport type { FC } from react;type Student {id?: number;name?: string;};interface PropsType {stus: Student[];}const Results: FCPropsType ({ stus }) {return (div classNamesearch{!stus.length ? (h1No Data/h1) : (stus.map((stu: Student) {return (div key{stu.id}div classNameinfoh1{stu.name}/h1/div/div);}))}/div);};export default Results;Results.test.tsximport { render } from testing-library/react;import { describe, expect, it } from vitest;import Results from ./Results.tsx;describe(Results, () {// 快照测试会在当前目录下生成__snapshots__文件夹和快照文件it(should renders correctly with no stus, () {const { asFragment } render(Results stus{[]} /);// 渲染快照结果是否与存档快照一致expect(asFragment()).toMatchSnapshot();});it(should renders correctly with some stus, () {const stus [{id: 1,name: Luna},];const { asFragment } render(Results stus{stus} /);// 渲染快照结果是否与存档快照一致expect(asFragment()).toMatchSnapshot();});});在第一次执行完测试用例后当前目录会生成以下文件【图片】后续的每次测试会将最新结果和这里保存的结果进行对比如果一致则代表测试通过反之则不然。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.tsximport type { FC } from react;interface PropsType {id?: number;name?: string;animal?: string;breed?: string;images?: string[];location?: string;}const Pet: FCPropsType (props) {const { name, animal, breed, images, location, id } props;let hero http://pets-images.dev-apis.com/pets/0.jpg;if (images?.length) {hero images[0];}return (div classNamepetdiv classNameimage-containerimg>import { render } from testing-library/react;import { StaticRouter } from react-router-dom/server;import { expect, test } from vitest;import Pet from ./Pet.tsx;test(displays a default thumbnail, async () {// 渲染组件const pet render(Pet /);// 异步等待获取指定的DOM元素const petThumbnail (await pet.findByTestId(thumbnail)) as HTMLImageElement;// 断言0.jpg包含在src的属性值中expect(petThumbnail.src).toContain(0.jpg);// 卸载组件pet.unmount();});有很多API可以断言一个元素是否存在例如toBeInTheDocument详细用法请查阅官方文档。expect(testDom).toBeInTheDocument();AI写代码5.2交互测试上面测试了组件能够按预期渲染单一个这样的用例是远远不够的我们还需要模拟用户交互行为来测试组件是否符合预期例如常见的点击、拖拽等。Carousel.tsximport type { FC, MouseEvent } from react;import { useState } from react;interface PropsType {images?: string[];}const Carousel: FCPropsType (props) {const { images [http://pets-images.dev-apis.com/pets/0.jpg] } props;const [active, setActive] useStatenumber(0);const handleIndexClick (event: MouseEvent) {const { index 0 } (event.target as HTMLImageElement).dataset;setActive(index);};return (div classNamecarouselimg>import { act, fireEvent, render } from testing-library/react;import { expect, test } from vitest;import Carousel from ./Carousel.tsx;test(lets users click on thumbnails to make them the hero, async () {const images [0.jpg, 1.jpg, 2.jpg, 3.jpg];const carousel render(Carousel images{images} /);const hero (await carousel.findByTestId(hero)) as HTMLImageElement;expect(hero.src).toContain(images[0]);for (let i 0; i images.length; i) {const image images[i];const thumb await carousel.findByTestId(thumbnail${i});act(() {// 模拟 click 用户事件fireEvent.click(thumb);});expect(hero.src).toContain(image);expect(Array.from(thumb.classList)).toContain(active);}});6.React Hook 测试这里的Hook是指业务中自定义封装的Hook我们知道Hook只能在函数组件中调用那如何来做单元测试呢RTL中提供了renderHook专门用来调用Hook。useSearch.tsimport { useState, useMemo } from react;/*** useSearch 数据过滤* param items 初始数组* return* searchTerm 搜索词* setSearchTerm 更新搜索词方法* filteredItems 过滤后的数据*/export const useSearch (items: any[]) {const [searchTerm, setSearchTerm] useState();const filteredItems useMemo(() {return items.filter((movie) movie.title.toLowerCase().includes(searchTerm.toLowerCase()));}, [items, searchTerm]);return {searchTerm,setSearchTerm,filteredItems,};};useSearch.test.tsimport { act, renderHook } from testing-library/react;import { describe, expect, it } from vitest;import { useSearch } from /hooks/__test__/useSearch.ts;describe(useSearch hook, () {// 测试返回默认搜索项 和 原始项目列表it(should return a default search term and original items, () {const items [{ title: Star Wars }];// renderHook 模拟hook执行环境const { result } renderHook(() useSearch(items));// result.current 为useSearch hook的返回值expect(result.current.searchTerm).toBe();expect(result.current.filteredItems).toEqual(items);});// 测试设置查询条件是否生效it(should return a filtered list of items, () {const items [{ title: Star Wars }, { title: Starship Troopers }];const { result } renderHook(() useSearch(items));// 反应所有的渲染和触发的事件都包装在 act 中。它负责在调用之后刷新所有效果并重新渲染。act(() {result.current.setSearchTerm(Wars);});expect(result.current.searchTerm).toBe(Wars);expect(result.current.filteredItems.length).toBe(1);expect(result.current.filteredItems).toEqual([{ title: Star Wars }]);});});7.异步、Mock测试7.1使用waitFor异步等待接口返回前端很多数据都是通过接口返回页面需要等待接口返回后才能渲染因此单元测试中的断言也需要等待使用waitFor可以实现。useMovies.tsexport const useMovies ():{ movies: Movie[], isLoading: boolean, error: any } {const [movies, setMovies] useState([]);const fetchMovies async () {try {setIsLoading(true);const response await fetch(https://swapi.dev/api/films);if (!response.ok) {throw new Error(Failed to fetch movies);}const data await response.json();setMovies(data.results);} catch (err) {//do something} finally {//do something}};useEffect(() {fetchMovies();}, []);return { movies }}useMovies.test.tsimport { renderHook, waitFor } from testing-library/react;import { describe, expect, it } from vitest;import { useMovies } from /hooks/__test__/useMovies.ts;describe(useMovies hook, () {//...it(should setTimeout movies, async () {const { result } renderHook(() useMovies());// 在达到超时值之前waitFor 可能会多次运行回调。请注意调用的数量受到超时和间隔选项的限制await waitFor(() {expect(result.current.isLoading).toBe(true);expect(result.current.movies).toEqual([{ title: Star Wars }]);expect(result.current.error).toBe(null);});});});waitFor的第二个参数是一个配置对象可以配置超时时间超过配置的上限后测试为不通过.// 默认间隔为50毫秒,超时时间是1000ms。第二个参数可以配置间隔和超时时间await waitFor(() {// ...},{timeout: 1000,});7.2使用spyOn拦截请求方法自定义mock第一种方法是真实向后端发送了请求在实际运用中可能不太合适。我们可以选择spyOn来拦截fetch自己mock接口返回值更加符合测试场景。import { renderHook, waitFor } from testing-library/react;import { afterAll, beforeAll, describe, expect, it, vi } from vitest;import { useMovies } from /hooks/__test__/useMovies.ts;describe(useMovies hook, () {// 通过vi.spyOn方法我们可以在不触发真正的 API 调用的情况下运行测试从而减少由于外部因素导致测试失败的机会。// 监视该global.fetch方法并模拟其实现以返回虚假响应const fetchSpy vi.spyOn(global, fetch);// 注册一个回调函数在开始运行当前上下文中的所有测试之前调用一次beforeAll(() {const mockResolveValue {ok: true,data: [{ title: Star Wars }],};// 接受一个值该值将在调用 mock 函数时返回fetchSpy.mockReturnValue(mockResolveValue as any);});// 测试 fetch异步获取数据it(should fetch movies, async () {const { result } renderHook(() useMovies());await waitFor(() {expect(result.current.isLoading).toBe(true);expect(result.current.movies).toEqual([{ title: Star Wars }]);expect(result.current.error).toBe(null);});});// 注册一个回调函数以便在当前上下文中所有测试运行完毕后调用一次。afterAll(() {// 将内部实现还原为原始函数// 还可以在 beforeEach 或 afterEach 中使用 mockClear()in方法来确保我们的测试完全隔离fetchSpy.mockRestore();});});通过调用vi.spyOn(global, fetch)拿到代理方法再调用mockReturnValue设置mock值以此来模拟接口返回这样更方便去断言。由于我们模拟了fetch方法的返回值因此需要在测试完成后使用mockRestore恢复其原始实现还可以使用该mockClear()方法清除所有mock的信息7.3测试生命周期beforeAll在当前文件的正式开始测试前执行一次适合做一些每次test前都要做的初始化操作比如数据库的清空以及初始化beforeEach在当前文件的每个test执行前都调用一次。afterAll在当前文件所有测试结束后执行一次适合做一些收尾工作比如将mock清除。afterEach在当前文件的每个test执行完后都调用一次。结尾这篇文章从单元测试的重要性、测试工具、测试实践三个方面带大家入门前端单元测试。相信大家认真学完后都能有收获感谢每一个认真阅读我文章的人礼尚往来总是要有的虽然不是什么很值钱的东西如果你用得到的话可以直接拿走这些资料对于【软件测试】的朋友来说应该是最全面最完整的备战仓库这个仓库也陪伴上万个测试工程师们走过最艰难的路程希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取