为什么选择Storybook进行可视化组件测试?

961 篇文章 1 订阅
555 篇文章 1 订阅

2024软件测试面试刷题,这个小程序(永久刷题),靠它快速找到工作了!(刷题APP的天花板)_软件测试刷题小程序-CSDN博客文章浏览阅读2.6k次,点赞85次,收藏12次。你知不知道有这么一个软件测试面试的刷题小程序。里面包含了面试常问的软件测试基础题,web自动化测试、app自动化测试、接口测试、性能测试、自动化测试、安全测试及一些常问到的人力资源题目。最主要的是他还收集了像阿里、华为这样的大厂面试真题,还有互动交流板块……_软件测试刷题小程序https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502我(作者)从事前端开发已有6年多的时间,主要使用 Angular(https://angular.io/),在 React (https://react.dev/)方面也积累了一年左右的经验。在这段时间里,我们使用 Jasmine (https://jasmine.github.io/)和 Karma (https://karma-runner.github.io/latest/index.html)测试Angular组件,使用Jest (https://jestjs.io/)测试 React 组件。

这两个测试库都有一个共同的局限性,那就是它们都不提供渲染功能,开发人员无法直观地查看他们正在测试的内容或组件在测试执行过程中的表现。因此,我曾观察到一些测试未能评估预期方面的情况,在某些情况下,测试最终什么也没测试到。

事实证明,对于希望为前端做出贡献的后端开发人员来说,组件测试是一项重大挑战。虽然他们渴望参与前端开发并完成横跨后端和前端的端到端(E2E)用户故事,但他们往往在组成组件测试方面感到吃力。这种困难甚至导致我们的前端开发人员在 E2E 测试中测试组件逻辑,而不是将其隔离开来,这主要是因为 E2E 测试提供了可视化反馈,因此制作 E2E 测试更加简单明了。

为什么选择 Storybook?

今年,我们开始开发模块化网络组件(https://module-federation.io/),以便与其他团队的产品实时无缝集成。这就需要为我们的网络组件创建全面的文档,确保其他团队可以集成这些组件,而无需联系我们进行说明。鉴于 Storybook 已经是我们组织内部广泛采用的工具,我们选择继续将其用于这一目的。

(注:本文参考Storybook 7.5版本)

与此同时,我们正在引入 Playwright 进行端到端(E2E)测试。有趣的是,我们发现 Storybook 将 Playwright 的可视化组件测试作为其功能的一部分,即交互测试。这个偶然的发现与我们的要求完全吻合。

当时,我们还考虑了其他两个可视化组件测试选项:Cypress 和 Playwright。然而,由于我在另一篇文章中详述的过去经历,Cypress 失去了青睐。此外,Playwright 的组件测试功能仍处于试验阶段,这让我们对将其引入企业级应用感到担忧。

最终,我们得出结论,将网络组件文档和测试结合起来更有意义。这种方法可以确保开发人员不会忽略新组件的文档,因为文档会作为测试过程的副产品自然出现。

交互测试的好处

事实证明,使用 Storybook 进行可视化组件测试是非常简单和友好的。我们利用它的功能对各种组件进行了测试,从简单明了的用户界面元素到涉及复杂用户界面和逻辑的大型组件。在过去的几个月中,我们从这种方法中收获了一些优势,在此重点介绍一下:

  • 易于编写测试:Storybook 采用与典型网络应用程序相同的方式渲染组件,从而简化了编写测试和用例(称为 "故事")的过程。这种方法允许使用类似 Playwright 的 Jest 语法对每个组件进行直接、孤立的测试,同时提供组件行为的实时可视化。

  • 组件文档:组件的输入和输出属性都有详细的文档说明,而且可以通过 Storybook 用户界面方便地进行修改。任何修改都会立即生效,组件会根据其属性输入进行渲染。

    你可以灵活地让 Storybook 自动检测组件的输入和输出,从而自动生成控件,如截图所示。我们对内部组件采用了这种方法,这些组件只在我们团队内部使用。但是,对于其他团队使用的网络组件,我们选择提供更广泛的文档。在这种情况下,Storybook 可以让你为每个控件添加额外的文档,如果有必要进行定制,甚至可以覆盖其类型。

图片

  • 实时交互:由于属性可以修改、组件可以渲染和交互,我们还可以查看组件触发的所有事件(输出)。

图片

  • 调试(Debugging):使用 Interactions 选项卡中提供的前后箭头,一步步进行测试非常简单。我们还提供了正常的浏览器开发工具用于调试。

图片

  • 模拟(Mocking)API:你可以选择让 API 调用以正常方式执行,也可以对其进行模拟。有几种不同的库可以做到这一点。我们目前使用的是一个名为 storybook-addon-mock (https://github.com/linearlabs-workspace/storybook-addon-mock)的库,它可以在用户界面上显示被模拟的内容;提供了一个不错的模拟概览。你还可以通过用户界面修改 API 响应或 HTTP 代码、响应延迟以及启用/禁用模拟。我们主要将其用于模块化网络组件。在我们的案例中,这些都是执行 HTTP 调用的复杂组件。

图片

  • 无头执行(Headless execution):在开发和调试过程中,所有这些测试都可以在浏览器上运行,这非常方便,但你很可能希望在 CI 管道中通过命令行运行测试。@storybook/test-runner (https://github.com/storybookjs/test-runner)库提供所需的一切。

  • 并行运行(Parallel runs):Storybook 的测试运行库开箱即支持并行化。虽然我还没有对其性能进行全面的基准测试,但我可以肯定地说,当我们在管道中使用双倍工人时,我们的测试速度至少快了一倍(我们的慢速 Jenkins 似乎能够处理)。

  • 测试覆盖率:如果在运行测试时使用--coverage 标志,Storybook 的测试运行库会为测试生成 lcov报告。然后,我们使用istanbul-merge (https://github.com/ljharb/istanbul-merge)将此报告与其他测试覆盖率报告合并,以提供统一的报告。

  • 控制台日志:Storybook 的测试运行库会在终端显示所有浏览器控制台日志。这有助于调试可能只在管道中失败的测试。

交互测试的不足

尽管 Storybook 已经取得了长足的进步,我们也不会恢复以前的可视化组件测试方法,但 Storybook 的某些方面仍有待进一步改进。以下是几个可以改进的方面:

  • 错误测试:Storybook 目前会默默吞下应用程序异常。这就意味着,如果你想根据抛出的异常来测试 ErrorBoundary(https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary),那就没戏了。我们也无法测试 HTTP 调用失败时网络组件的行为(允许真正的 HTTP 调用发生);相反,我们必须模拟响应,如下图所示。这是因为,如果我们让真正的 HTTP 调用执行,而后端响应的不是 2xx HTTP 状态代码,那么请求承诺就永远不会完成,测试就会超时失败。这对我们来说是一个相当大的问题,因为我们本想测试与后端集成的错误用例。

图片

Storybook 语法:Storybook 中用于创建故事、文档和测试的语法非常独特,并且不遵循 describe/it 其他广泛认可的测试库所采用的更传统的语法。值得注意的是,适应这种新颖的语法可能是一个学习曲线,可能需要一些时间才能熟悉。在考虑 Storybook 是否适合团队需求的工具时,应该将这段调整期考虑到你的评估中。


// ---------------------------------------------------------------------------
// Define decorators for your stories, this one adds your app theme to
// the components in Storybook
exportconstwithTheme: Decorator = (StoryFn) => {
  return (
    <ThemeProvider theme={theme}>
      <StoryFn />
    </ThemeProvider>
  );
};

// ---------------------------------------------------------------------------
// Define the story as the default export
// With this configuration, Storybook will auto-detect and create the controls
// based on the component props
exportdefault {
  title: 'Internal-Components/ThousandSeparatorNumberFormat',
  component: ThousandSeparatorNumberFormat,
  decorators: [withTheme],
} asMeta<typeofThousandSeparatorNumberFormat>;

typeStory = StoryObj<typeofThousandSeparatorNumberFormat>;

// This is the template for all upcoming stories
constTemplate: StoryFn<typeofThousandSeparatorNumberFormat> = (args) => (
  <TextField
    inputProps={{ ...(args as object) }}
    InputProps={{
      inputComponent: ThousandSeparatorNumberFormat as any,
    }}
  />
);

// ---------------------------------------------------------------------------
// Use-case: thousands formatting with suffix without max value
exportconstWithoutMaxValue: Story = Template.bind({});
WithoutMaxValue.args = {
  name: 'Thousands Number Formatter',
  suffix: '$',
  customTextIndent: '2px',
  disableMaxValue: true,
  customDataTestId: 'thousand-separator-number-format-input',
};
WithoutMaxValue.play = async ({ args, canvasElement, step }) => {
  // your component will be rendered within the storybook canvas area
  // if you are testing modals, this will not work and you will need to use
  // screen.getByTestId(...) instead of canvas.getByTestId(...) where:
  // import { screen } from '@storybook/testing-library';
  const canvas = within(canvasElement);

  // we use steps to group tests in small components like this one, or
  // in more complex components, to group logical test steps
  awaitstep('Each digit triggers a change event', async () => {
    userEvent.clear(canvas.getByTestId(args.customDataTestId ?? ''));
    userEvent.type(canvas.getByTestId(args.customDataTestId ?? ''), '123456');

    expect(canvas.getByDisplayValue('123,456 $')).toBeInTheDocument();
    awaitwaitFor(() =>expect(args.onChange).toHaveBeenCalledTimes(6));
    awaitwaitFor(() =>
      expect(args.onChange).toHaveBeenLastCalledWith({
        target: {
          name: args.name,
          value: '123456',
        },
      })
    );
  });
};

  • 缺乏 beforeEach/afterEach:Storybook 缺乏在每次测试之前和/或之后执行代码的内置机制。但是,有一些可用的解决方法,涉及使用装饰器来封装和自定义被测组件,能够根据需要实现在每次测试之前运行的代码。需要注意的是,虽然存在在每次测试之前执行代码的解决方法,但目前在 Storybook 中没有已知的在每次测试之后运行代码的解决方法。

  • 报告:虽然 Storybook 的测试运行程序确实提供了覆盖率报告和 JUnit 报告,但这些报告仅在 CI 管道中发生故障时为调试提供有限的支持。Playwright 的与众不同之处在于其全面且详细的开箱即用报告,包括屏幕截图、视频和用于有效调试的完整 DOM。Storybook 目前缺乏一份报告来整合所有正在进行的测试、它们的执行时间,以及最重要的失败测试用例的详细信息。这些信息可能包括屏幕截图、视频、所有 Storybook 选项卡的访问权限等等。结合如此全面的报告功能将大大增强 Storybook 的调试能力。

  • 测试运行重试:Storybook 不提供重试单个失败测试的方法。Jest 和 Playwright 都为此提供了配置选项,但 Storybook 没有。

  • 速度:正如预期的那样,在测试中渲染组件确实会增加测试执行时间。在我们的管道中,我们观察到,与 Jest 测试相比,这些测试的运行时间大约是 Jest 测试的三倍,尽管我们尚未进行深入的基准测试,并且我们允许在其中一些 Storybook 测试中执行 HTTP 调用。尽管速度有所下降,但我们的团队发现可视化带来的优势超过了这种性能权衡。

  • Headless run需要Storybook运行:通过命令行执行Storybook测试时,目前需要手动启动Storybook应用程序并确认其运行顺利才能运行测试。如果将生成 Storybook 的过程集成到运行器命令本身中,会更加方便和高效,从而简化开发人员的工作流程。

结论

当你无法在测试过程的每个阶段直观地检查 UI 组件的外观时,测试 UI 组件可能是一项具有挑战性的工作。这种抽象级别可能会导致开发人员无意中测试与最初意图不同的方面。可视化组件测试框架的出现显著改善了开发人员测试组件的体验。即使这些测试可能运行速度较慢,测试的可访问性的提高也会激励开发人员编写更全面的测试,从而提高软件的整体质量。

行动吧,在路上总比一直观望的要好,未来的你肯定会感谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入群: 786229024,里面有各种测试开发资料和技术可以一起交流哦。

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值