前端测试最强教程 (2/n)- vitest实现react集成测试

前言

上文写了一个组件的单测,实现了 100%覆盖率,接下来就引出了另一个问题,如何覆盖所有的代码?每个组件写一个单测?每个都 mock 一遍?

这是所有尝试开始写测试的同学遇到的最头疼的问题,无穷无尽的 mock和样板代码。并且有的组件内部函数还很难被调用到,需要抽成 util 再写一个单测。

这个问题我之前也遇到了,解决的办法就是集成测试

集成测试 (英语:Integration testing),又称组装测试 ,即对程序模块采用一次性或增值方式组装起来,对系统的接口进行正确性检验的测试工作。整合测试一般在单元测试之后、系统测试之前进行。实践表明,有时模块虽然可以单独工作,但是并不能保证组装起来也可以同时工作

那么接下来我们就来实现一个集成测试的架子。 其实 react应用就是由无数个小组件构成的大组件,那么我们直接在测试里面 render 整个 App 不就行了吗?非常简单

step 1: 在测试目录新建文件 app-context.tsx

这个文件的作用就是统一测试架构的上下文,并且能够统一管理。

我就直接贴代码了,通过注释来介绍每一行的作用。

由于我们的测试项目非常简单,所以这个上下文也非常简单。真实项目的上下文肯定是这个代码量的几十几百倍,并且构造起来也是很困难的。

ts 复制代码
// app-context.tsx
import { MemoryRouter } from 'react-router-dom' // react-router 在测试中需要使用 MemoryRouter 来替换 BrowserRouter 
import APP from '../App' // 应用入口
import { render, cleanup, within } from '@testing-library/react' // react 测试依赖
import { vi } from 'vitest' // vitest 的工具函数集,提供了常用的方法,比如 mock spy timer 等
import { fakeHttpHandler } from './fake-http-handler' // mock 接口的返回数据
vi.useFakeTimers() // 代理定时器相关
window.fetch = fakeHttpHandler // 重写 window.fetch
export const createAppContext = () => {
    // 整个应用
    const container = render(<MemoryRouter>
        <APP />
    </MemoryRouter>)
    // 抽一些常用的方法
    const inSideBar = () => {
        return within(container.getByTestId('side-bar'))
    }
    return {
        container,
        inSideBar,
        cleanup,
    }
}
// 导出 appContext 的类型
export type AppContext = ReturnType<typeof createAppContext>
ts 复制代码
// fake-http-handler.ts
// 重写一个 fetch 方法,让它能能够写死返回需要的数据
import { fakeResponse } from "./fake-response"

export const fakeHttpHandler = async (...args: Parameters<typeof fetch>) => {
    console.log(args[0])
    const res = {
        json: async () => {
            return { data: fakeResponse[args[0] as string] }
        },
    } as Awaited<ReturnType<typeof fetch>>
    return res
}
// fake-response.ts
// 我直接把当时接口的返回值 copy 下来。
export const fakeResponse: Record<string, object> = {
    '/hupu/api/v2/bbs/walkingStreet/threads?page=1':{
        threadList: [data1,data2,...]
    }
}

写完这几个文件后,最简单版集成测试的的框架已经搭好了,接下来就可以愉快的写测试了。

step2: 写集成测试

通过我们封装的这个上下文,创建一个测试就非常简单了,大致的样板代码为

ts 复制代码
import { afterEach, beforeEach, vi, describe, expect, it } from "vitest";
import { AppContext, createAppContext } from "../app-context";
describe('G: 加载应用', () => {
    let _: AppContext
    beforeEach(() => {
        _ = createAppContext()
    })
    afterEach(() => {
        _.cleanup()
    })
    describe('W: 数据加载中', () => {
        it('T: 会展示 loading', () => {})
            describe('W: 数据加载完成', () => {
                it('T: 会展示文件列表', () => {})
            })
    })
    
})

然后我们对整个应用做 GWT case design,做完之后开始写测试代码,现在借助 ai 功能,写测试代码是非常快的,如果你的测试框架搭建的足够完善,ai 生成的代码准确度就越高,我们只需要做一些小修改即可,比如如何等待异步事件结束,如何模拟用户事件等。此处不再赘述,代码在这里,一共 50 行。 github.com/alpacachen/...

这两步结束后我们就有了第一个集成测试的 test case。跑一下测试覆盖率看看

效果立竿见影,我们之前一个组件的单测就 77 行,现在有了集成测试,50 几行代码就可以实现几乎全覆盖。 并且看一下我们的测试报告 npm run test 是不是一目了然,清晰直观,这就是为什么我说,好的测试 case 胜过一切项目文档

总结

这一篇文章介绍了搭建集成测试的流程,这其实没有任何难度,难得是想到这个思路。同时我展示了一份好的测试用例 demo,希望能帮助到大家。

一些感想

我是今天开始写文章才认真看了看掘金的推荐流,只能说前端圈还需努力,希望大家少一些浮躁,多一些沉淀。比如写测试这件事非常锻炼人心智,浮躁的人是没有办法静下心来找出 corner case 并且写补全测试的。因为写测试是对未来的投资,一份测试代码,刚写出来的时候是一文不值的,他的价值会随着时间的增加而增加,如果你写的测试测试代码,五年后还在守护着系统稳定运行,那它就是"价值连城"的。

相关推荐
EricWang13588 分钟前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning8 分钟前
React.lazy() 懒加载
前端·react.js·前端框架
web行路人18 分钟前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
超雄代码狂40 分钟前
ajax关于axios库的运用小案例
前端·javascript·ajax
长弓三石1 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
小马哥编程1 小时前
【前端基础】CSS基础
前端·css
嚣张农民1 小时前
推荐3个实用的760°全景框架
前端·vue.js·程序员
周亚鑫1 小时前
vue3 pdf base64转成文件流打开
前端·javascript·pdf
Justinc.2 小时前
CSS3新增边框属性(五)
前端·css·css3
neter.asia2 小时前
vue中如何关闭eslint检测?
前端·javascript·vue.js