React 测试库 - FAQ

news/2024/7/15 17:40:50 标签: react.js, 前端, 前端框架, 单元测试
1、如何测试 input onChange 事件?
import React from 'react'
import {render, fireEvent} from '@testing-library/react'

test('change values via the fireEvent.change method', () => {
  const handleChange = jest.fn()
  const {container} = render(<input type="text" onChange={handleChange} />)
  const input = container.firstChild
  fireEvent.change(input, {target: {value: 'a'}})
  expect(handleChange).toHaveBeenCalledTimes(1)
  expect(input.value).toBe('a')
})

test('select drop-downs must use the fireEvent.change', () => {
  const handleChange = jest.fn()
  const {container} = render(
    <select onChange={handleChange}>
      <option value="1">1</option>
      <option value="2">2</option>
    </select>,
  )
  const select = container.firstChild
  const option1 = container.getElementsByTagName('option').item(0)
  const option2 = container.getElementsByTagName('option').item(1)

  fireEvent.change(select, {target: {value: '2'}})

  expect(handleChange).toHaveBeenCalledTimes(1)
  expect(option1.selected).toBe(false)
  expect(option2.selected).toBe(true)
})

test('checkboxes (and radios) must use fireEvent.click', () => {
  const handleChange = jest.fn()
  const {container} = render(<input type="checkbox" onChange={handleChange} />)
  const checkbox = container.firstChild
  fireEvent.click(checkbox)
  expect(handleChange).toHaveBeenCalledTimes(1)
  expect(checkbox.checked).toBe(true)
})

如果你曾经使用过 Enzyme 或者 React 的 TestUtils,你可能习惯于像这样修改输入:

input.value = 'a'
Simulate.change(input)

我们不能用 React 测试库(React Testing Library)来做这件事,因为 React 实际上会跟踪你在输入上赋值给 value 属性的任何时间,所以当你触发 change 事件时,React 认为 value 实际上并没有改变。

这对 Simulate 有效,因为它们使用内部 API 来触发特殊的模拟事件。而 React 测试库,我们尽量避免实现细节,以使你的测试更具弹性。

因此,我们为 change 事件处理程序设置了以 React 无法跟踪的方式设置属性的方式。这就是为什么你必须将 value 作为 change 方法调用的一部分传递的原因。

2、我可以用这个库编写单元测试吗?

当然可以!您可以使用这个库编写单元测试和集成测试。如果您想对高级组件进行单元测试,请参见下文以了解如何模拟依赖项(因为这个库故意不支持浅渲染)。此项目中的测试显示了几个使用该库进行单元测试的示例。

编写测试时,请记住:测试越接近软件的使用方式,它就越能给您信心。

3、如果我不能使用浅渲染,我如何在测试中模拟组件?

总的来说,你应该避免 mock 组件(参见指导原则部分)。但是,如果你需要的话,那么尝试使用 Jest 的 mock 功能。我发现特别有用的一种情况是用于动画库。我不想让我的测试等待动画结束。

jest.mock('react-transition-group', () => {
  const FakeTransition = jest.fn(({children}) => children)
  const FakeCSSTransition = jest.fn(props =>
    props.in ? <FakeTransition>{props.children}</FakeTransition> : null,
  )
  return {CSSTransition: FakeCSSTransition, Transition: FakeTransition}
})

test('you can mock things with jest.mock', () => {
  const {getByTestId, queryByTestId} = render(
    <HiddenMessage initialShow={true} />,
  )
  expect(queryByTestId('hidden-message')).toBeTruthy() // we just care it exists
  // hide the message
  fireEvent.click(getByTestId('toggle-message'))
  // in the real world, the CSSTransition component would take some time
  // before finishing the animation which would actually hide the message.
  // So we've mocked it out for our tests to make it happen instantly
  expect(queryByTestId('hidden-message')).toBeNull() // we just care it doesn't exist
})

请注意,因为它们是 Jest 模拟函数(jest.fn()),如果你愿意,你也可以对它们进行断言。

打开完整的测试以查看完整示例。

这看起来比浅渲染(shallow rendering)需要更多的工作(实际上也确实如此),但只要你模拟的东西足够接近你要模拟的东西,它就会给你更多的信心。

如果你想把事情做得更像浅渲染,那么你可以尝试这样做。

要了解 Jest 模拟函数的工作原理,请阅读我的博客文章:“但究竟,什么是 JavaScript 模拟函数?”。

4、关于enzyme,为什么会出现“结构复杂、特征繁多”和“鼓励不良的测试实践”的情况?

大多数破坏性特性都与鼓励测试实施细节有关。 首先,这些是浅渲染,允许通过组件构造函数选择渲染元素的API,以及允许您获取并与组件实例(及其状态/属性)进行交互的API(大多数酶的包装API都允许这样做)。

这个库的指导原则是:

你的测试越接近你的软件使用方式,它们能给你的信心就越多。 - 2018年2月17日

由于用户不能直接与您的应用程序的组件实例进行交互,断言其内部状态或它们渲染的组件,或调用其内部方法,因此在测试中进行这些操作会降低它们能够给予的信心。

这并不是说从未有用例去做这些事情,因此应该能够完成,只是不是测试和反应组件的默认和自然方式。

5、为什么快照差异比较不起作用?

如果你使用 snapshot-diff 库来保存快照差异,它将无法直接工作,因为这个库使用了可变的DOM。变化不会返回新的对象,所以 snapshot-diff 会认为它是同一个对象并避免对它进行差异分析。

幸运的是,有一个简单的方法可以让它工作:在将DOM传递给 snapshot-diff 时克隆它。它看起来像这样:

const firstVersion = container.cloneNode(true)
// Do some changes
snapshotDiff(firstVersion, container.cloneNode(true))
6、该如何修复“更新未被 act(...) 包装”的警告?

这个警告通常是由异步操作引起的,该操作在测试结束后触发更新。有两种方法可以解决此问题:

  1. 使用 waitFor 或 find* 查询等异步实用工具,在测试中等待操作结果。例如:const userAddress = await findByLabel(/address/i)。
  2. 对异步操作进行模拟,使其不触发状态更新。

一般来说,方法1更受推崇,因为它更符合用户与应用交互的预期。

此外,当你在考虑如何编写能够给你信心的测试并避免这些警告时,你可能会发现这篇博客文章很有帮助。

7、我应该测试组件树的哪个级别?子级、父级还是两者都要?

遵循这个库的指导原则,理解测试是如何围绕用户体验和与应用功能的交互来组织的,而不是围绕具体的组件本身,这是很有用的。在某些情况下,例如对于可重复使用的组件库,将开发人员包含在测试用户列表中,并分别测试每个可重复使用的组件可能是有用的。在其他情况下,组件树的特定分解只是实现细节,测试该树中的每个组件可能会导致问题(见https://kentcdodds.com/blog/avoid-the-test-user)。

在实践中,这通常意味着测试组件树的高级部分以模拟真实的用户交互。至于是否值得在此基础上进行更高或更低级别的测试,这取决于权衡和成本效益(有关不同级别的测试的更多信息,请参见https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests)。

有关此主题的更深入的讨论,请观看此视频。


http://www.niftyadmin.cn/n/5436888.html

相关文章

【云开发笔记No.5】DevOps的价值

一、DevOps的价值 在软件开发生命周期中&#xff0c;DevOps作为一种文化、实践和工具链的集合&#xff0c;为组织带来了显著的价值。其价值不仅体现在提高软件交付速度和质量上&#xff0c;还表现在增强团队协作、降低运维成本、提升客户满意度等多个方面。 首先&#xff0c;…

Jenkins-pipeline流水线构建完钉钉通知

添加钉钉机器人 在钉钉群设置里添加机器人拿出Webhook地址&#xff0c;设置关键词 Jenkins安装钉钉插件 Dashboard > 系统管理 > 插件管理&#xff0c;搜索构建通知&#xff0c;直接搜索Ding Talk也行 安装DingTalk插件&#xff0c;重启Jenkins 来到Dashboard > 系…

sentinel黑白名单权限控制

黑白名单权限控制 规则配置 规则创建 创建一个 AuthorityRule 规则对象三个关键要素 setStrategy: 黑白名单类型setResource: 规则和资源的绑定关系setLimitApp: 限制的来源 调用 AuthorityRuleManager.loadRules()加载规则 监听器实例化和管理 AuthorityPropertyListener…

PyTorch的向量化思维,以及Tensor、nn接口

文章目录 PyTorch的向量化思维,以及Tensor、nn接口大语言模型的向量化思路核心原理关键步骤关键技术PyTorch中的向量化`torch.nn` 是 PyTorch 中用于构建和训练神经网络的核心模块主要特点:1. 层(Layers)2. 模型(Modules)3. 损失函数(Loss Functions)4. 实用函数(Util…

23-分支和循环语句_习题练习

1、转换以下ASClI码为对应字符并输出他们&#xff1a;73,32,99, 97,110,32,100,111,32,105,116,33 输入&#xff1a;无 输出&#xff1a;一行输出转换题目中给出的所有ASClI码对应的字符&#xff0c;无需以空格隔开。 输入&#xff1a; int main() {int i 0;int arr[] { …

VTK----VTK的事件机制

事件的发送和接收对于一个应用或系统来说是一个基本的功能,所以一些通用的库对应地也建立了自己的一套管理事件的机制,例如QT、VTK都有自己的事件管理机制。VTK库中定义了很多的事件,这些事件是如何进行管理的,下面从三个方面来详细的说明。 1 事件的管理 在讲述VTK的事件…

如何在wps的excel表格里面使用动态gif图

1、新建excel表格&#xff0c;粘贴gif图到表格里面&#xff0c;鼠标右键选择超链接。 找到源文件&#xff0c; 鼠标放到图片上的时候&#xff0c;待有个小手图标&#xff0c;双击鼠标可以放大看到动态gif图。 这种方式需要确保链接的原始文件位置和名称不能变化&#xff01;&a…

【Linux】日常使用命令(三)

文章目录 **cal 命令****date 命令****bc 命令****Linux下玩小游戏**&#xff1a; cal 命令 功能描述: cal 命令用于显示日历。 常用选项: -3&#xff1a;显示前一个月、当前月和下一个月的日历。-y&#xff1a;显示整年的日历。 常用示例: # 示例 1: 显示当前月的日历 cal# …