前端单元测试,更进一步

9f7bafb33fbb50aaf7204fb4f421b456.png

前端测试@2022

如果从 2014 年 Jest 的第一个版本发布开始计算,前端开发领域工程化的单元测试能力已经发展了八年有余。

c962cd6caccea07a236f07d683b59cea.png

Jest 集成了 Jasmine 等以往各种被证明有效的单元测试框架和断言等工具,也可以用来完成包含外部接口服务的集成测试等。

最近几年热门的 vite 打包工具配套的 vitest,也是完全兼容 Jest 工具栈的;除了本身相比于 Jest 带来了比较大的性能提升之外,vitest 还提供了更好的 ESM 等支持。一般也用 @testing-library 来搭配 vitest,提供 DOM 等核心测试能力。

075145e88ebcb68e695cca994a9d3645.png

Storybook 则在浏览器环境中,为 UI 组件的单独编写和测试提供了可视化的、可交互的、与具体业务项目无关的单独运行环境;无论是 web 项目还是混合式的桌面应用,都可以不理会繁复的项目配置和依赖,把组件级别的开发在 Storybook 中快速完成。

bf447847974f2605f1c9ab2983fcb366.png

在测试分层金字塔模型中,最终还需要立足真实业务项目的 UI 测试,也就是终端用户(或 QA 测试人员)到终端设备的 E2E(end to end) 测试

一般所说的 自动化测试 指的大都是对于 E2E 测试的自动化。Selenium 是自动化测试的常用工具,但新兴的 Playwright 显然得到了越来越多的青睐;后者还能更好地支持 electron 等桌面开发项目。

play 一下

在开发实践中对比几种测试,Jest/vitest 单元测试易于开发人员编写,但其运行在命令行下,不够直观;而 Storybook 展示直观,却大部分只能靠开发者人工检查其有效性,由于无法集成到 pre-commit 等开发流程中,也容易重蹈早期 Jasmine 等基于浏览器页面单测用例的覆辙 -- 编写简单但很容易过时失效。

较新版本的 Storybook 中引入了 交互式测试(Interaction Test) 的概念,用法也极为简单,只需要为既有的 UI 用例编写一个 play() 函数 就可以了。

// LoginForm.stories.js|jsx

import React from 'react';
import { within, userEvent } from '@storybook/testing-library';
import { expect } from '@storybook/jest';
import { LoginForm } from './LoginForm';

export default {
  title: 'Form',
  component: LoginForm,
};

const Template = (args) => <LoginForm {...args} />;

export const EmptyForm = Template.bind({});

export const FilledForm = Template.bind({});
// 为具名用例增加 play()
FilledForm.play = async ({ canvasElement }) => {
  const canvas = within(canvasElement);

  // 复用单测中的 testing-library 库模拟用户行为
  await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');
  await userEvent.type(canvas.getByTestId('password'), 'a-random-password');
  await userEvent.click(canvas.getByRole('button'));

  // 直接用 jest/vitest 等提供的断言函数
  await expect(
    canvas.getByText(
      'Everything is perfect. Your account is ready and we should probably get you started!'
    )
  ).toBeInTheDocument();
};

类似单测在命令行中的红绿结果,交互式测试的每个步骤、其成功失败,都会显示在相应的面板中:

c6e71140d33f2795d1c4c90380bf9de0.png

复用测试用例

不难发现,工具栈相同、写法无异,play 函数对于习惯了写单元测试的前端开发者来说并不陌生,或者可以说是零门槛的,play 函数中的代码就是标准的单测代码。那么我们也没有任何理由让这部分测试代码游离在覆盖率统计之外,或是再去单测中编写重复的代码了。

需要做的也非常简单,直接在单测中 import 后 play 就是了:

// foo.spec.jsx

import { render } from '@testing-library/react';
import { FooUISpec } from '../Foo.stories';

it('Checks by storybook', async () => {
  const { container } = render(<FooUISpec />);
  await FooUISpec.play({ canvasElement: container });
});

总结

现在,我们可以让 Storybook 和单元测试分享测试用例,甚至可以在 Playwright 中调用 Storybook 服务后再编写自动化测试 -- 后者这里不展开讨论了;总之,测试工具的发展,给了前端开发者更直观编写测试用例的手段,最终也更好地保证了前端项目的开发质量,以及代码编写的合理性。

f368b2a28ffdff85f88be9c52b8b8955.png924f8d36439c68e3deae4cf96b346e40.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值