六、组件测试
Demo: 这里列举了一个简单的场景
user.ts: 获取用户角色身份
import axios from "axios"; // 类型:用户角色身份 export type UserRoleType = "user" | "admin"; // 接口:返回 export interface GetRoleRes { userType: UserRoleType; } // 函数:获取用户角色身份 export const getUserRole = async () => { return axios.get<GetRoleRes>("https://xxx.xx.com/api/role"); };
业务组件/Auth/Button/index.tsx(缩略代码)
import React, { FC, useEffect, useState } from "react"; ... // 身份文案 Mapper const mapper: Record<UserRoleType, string> = { user: "用户", admin: "管理员", }; const Button: FC<Props> = (props) => { const { children, className, ...restProps } = props; const [userType, setUserType] = useState<UserRoleType>(); // 获取用户身份,并设值 const getLoginState = async () => { const res = await getUserRole(); setUserType(res.data.userType); }; useEffect(() => { getLoginState().catch((e) => message.error(e.message)); }, []); return ( <Button {...restProps}> {mapper[userType!] || ""} {children} </Button> ); }; export default Button;
测试用例button.test.tsx
import { render, screen } from "@testing-library/react"; import Button from "components/Button"; import React from "react"; describe('Button', () => { it('可以正常展示', () => { render(<Button>登录</Button>) expect(screen.getByText('登录')).toBeDefined(); }); })
上面这代码只是一个简单的Demo测试
测试组件功能
mockAxios.test.tsx
import React from "react"; import axios from "axios"; import { render, screen } from "@testing-library/react"; import Button from "components/Button"; describe("Button Mock Axios", () => { it("可以正确展示用户按钮内容", async () => { jest.spyOn(axios, "get").mockResolvedValueOnce({ // 其它的实现... data: { userType: "user" }, }); render(<Button>你好</Button>); expect(await screen.findByText("用户你好")).toBeInTheDocument(); }); it("可以正确展示管理员按钮内容", async () => { jest.spyOn(axios, "get").mockResolvedValueOnce({ // 其它的实现... data: { userType: "admin" }, }); render(<Button>你好</Button>); expect(await screen.findByText("管理员你好")).toBeInTheDocument(); }); });
当然,我们也可以不mock,而是使用 Http Mock 工具:msw
Mock Http
代码如下:
/mockServer/handlers.ts
import { rest } from "msw"; const handlers = [ rest.get("https://xxx.xx.com/api/role", async (req, res, ctx) => { return res( ctx.status(200), ctx.json({ userType: "user", }) ); }), ]; export default handlers;
/mockServer/server.ts
import { setupServer } from "msw/node"; import handlers from "./handlers"; const server = setupServer(...handlers); export default server;
/jest-setup.ts
import server from "./mockServer/server"; beforeAll(() => { server.listen(); }); afterEach(() => { server.resetHandlers(); }); afterAll(() => { server.close(); });
最后测试用例代码:
// 偏向真实用例 import server from "../../mockServer/server"; import { rest } from "msw"; import { render, screen } from "@testing-library/react"; import Button from "components/Button"; import React from "react"; import { UserRoleType } from "apis/user"; // 初始化函数 const setup = (userType: UserRoleType) => { server.use( rest.get("https://xxx.xx.com/api/role", async (req, res, ctx) => { return res(ctx.status(200), ctx.json({ userType })); }) ); }; describe("Button Mock Http 请求", () => { it("可以正确展示普通用户按钮内容", async () => { setup("user"); render(<Button>广东</Button>); expect(await screen.findByText("用户你好")).toBeInTheDocument(); }); it("可以正确展示管理员按钮内容", async () => { setup("admin"); render(<Button>靓仔</Button>); expect(await screen.findByText("管理员你好")).toBeInTheDocument(); }); });
setup 函数,在每个用例前初始化 Http 请求的 Mock 返回。
七、小结
Jest的功能远不止于此,还能做性能测试、自动化测试等等
在我们阅读完官方文档后,我们一定会进行更深层次的学习,比如看下框架底层是如何运行的,以及源码的阅读。
这里广东靓仔给下一些小建议:
- 在看源码前,我们先去官方文档复习下框架设计理念、源码分层设计
- 阅读下框架官方开发人员写的相关文章
- 借助框架的调用栈来进行源码的阅读,通过这个执行流程,我们就完整的对源码进行了一个初步的了解
- 接下来再对源码执行过程中涉及的所有函数逻辑梳理一遍