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

前言

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

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

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

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

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

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

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

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

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

// 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>
// 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: 写集成测试

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

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。跑一下测试覆盖率看看

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

总结

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

一些感想

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

原文链接:https://juejin.cn/post/7344260010853023779 作者:阿古达木

(0)
上一篇 2024年3月10日 下午4:37
下一篇 2024年3月10日 下午4:47

相关推荐

发表回复

登录后才能评论