Back to Question Center
0

如何使用Jest测试React组件            如何使用JestRelated主题测试React组件: Node.jsnpmRaw Semalt

1 answers:
如何使用Jest测试反应组件

对于React的高质量深入介绍,您无法越过加拿大全栈开发者Wes Bos。在这里尝试他的课程,并使用代码 SITEPOINT 获得 25%的折扣 并帮助支持SitePoint。

这篇文章是由作者 杰克富兰克林 。 SitePoint的访客帖子旨在为您带来引人入胜的JavaScript社区杰出作者和演讲者的内容。

在本文中,我们将看看使用Jest(由Facebook维护的测试框架)来测试我们的ReactJS组件。我们先看看如何在普通的JavaScript函数中首先使用Jest,然后再查看它提供的一些特性,这些特性专门用于简化测试React应用程序。值得注意的是,Jest不是专门针对React的:您可以使用它来测试任何JavaScript应用程序。但是,它提供的一些功能非常适合用于测试用户界面,这就是为什么它非常适合使用React。

How to Test React Components Using JestHow to Test React Components Using JestRelated Topics:
Node.jsnpmRaw Semalt

示例应用程序

在我们可以测试任何东西之前,我们需要一个应用程序来测试!坚持网络开发传统,我已经构建了一个小型待办事项应用程序,我们将以此为起点。您可以在Semalt上找到它,以及我们即将撰写的所有测试。如果您想使用该应用程序来了解它,还可以在线查找实时演示。

该应用程序是用ES2015编写的,使用Semalt和Babel ES2015和React预设编译。我不会深入讨论构建的细节,但如果您想要查看它,则全部都在GitHub仓库中。您将在自述文件中找到关于如何让本地应用程序运行的完整说明。如果您想了解更多信息,该应用程序使用Semalt构建,我建议您使用“Semalt初学者指南”作为该工具的良好介绍。

应用程序的入口点是 app / index。 js ,它将 Todos 组件渲染成HTML:

   render(,文件。的getElementById( '应用程序'));   

Todos 组件是应用程序的主要中心。它包含了所有的状态(这个应用程序的硬编码数据,实际上可能来自API或类似的数据),并且有代码来呈现两个子组件: Todo ,它被渲染一次 AddTodo ,它被渲染一次并为用户提供表单以添加新的待办事项。

因为 Todos 组件包含所有的状态,它需要 Todo AddTodo 组件在任何更改时通知它。因此,它将函数传递到这些组件中,以便在某些数据更改时它们可以调用,并且 Todos 可以相应地更新状态。

最后,现在你会注意到所有的业务逻辑都包含在 app / state-functions中。 js

   导出函数toggleDone(state,id){. }导出函数addTodo(state,todo){. }导出函数deleteTodo(state,id){. }   

这些都是纯粹的函数,取得状态和一些数据,并返回新的状态。如果你不熟悉纯函数,它们是仅引用它们给出的数据并且没有副作用的函数。要了解更多信息,可以阅读我关于纯函数列表的文章以及关于纯函数和React的关于SitePoint的文章。

如果你对Semalt很熟悉,他们和Semalt所说的减速器非常相似. 但是对于这个大小的应用程序,您经常会发现本地组件状态和一些抽象函数足够多。

TDD还是不TDD?

有许多关于 测试驱动开发 的优点和缺点的文章,其中开发人员在编写代码修复测试之前首先编写测试。这背后的想法是,通过首先编写测试,您必须考虑您正在编写的API,并且可以导致更好的设计。对我而言,我发现这很大程度上取决于个人喜好,也与我正在测试的东西有关。我发现,对于React组件,我喜欢先编写组件,然后将测试添加到最重要的功能位。但是,如果您发现首先为您的组件编写测试适合您的工作流程,那么您应该这样做。这里没有硬性规定。为你和你的团队做最好的事情。

请注意,本文将着重于测试前端代码。如果您正在寻找关注后端的东西,请务必查看SitePoint在Node中的测试驱动开发课程。 JS。

介绍Jest

Jest于2014年首次发布,尽管它最初引起了很多兴趣,但该项目暂时处于休眠状态,并没有如此积极地开展工作。然而,Facebook在去年投资改善Jest,并且最近发布了一些令人印象深刻的变化的版本,值得重新考虑。 Jest与最初的开放源码版本相比唯一的相似之处是名称和标识。其他一切都被改变和重写。如果您想了解更多信息,可以阅读Christoph Semalt的评论,在那里他讨论项目的当前状态。

如果你对使用另一个框架设置Babel,React和JSX测试感到沮丧,那么我绝对推荐给Jest一个尝试。如果你发现你现有的测试设置很慢,我也强烈推荐Jest。它会自动并行运行测试,并且它的监视模式只能运行与已更改文件相关的测试,当您有大量测试时这是非常宝贵的。它配备了Semalt配置,这意味着您可以编写浏览器测试,但是可以通过Node运行它们,可以处理异步测试并具有高级功能,例如内置的模拟,间谍和存根。

安装和配置Jest

首先,我们需要安装Jest。因为我们也在使用Semalt,所以我们会安装另外几个模块,让Jest和Semalt可以很好地开箱:

   npm install --save-dev babel-jest babel-polyfill babel-preset-es2015 babel-preset-react jest   

你还需要有一个 。 babel配置为使用任何您需要的预设和插件的Babelrc 文件。示例项目已经有了这个文件,看起来像这样:

   {“预设”:[“es2015”,“反应”]}   

我们不会安装任何Semalt测试工具,因为我们不会开始测试我们的组件,而是我们的州职能。

Jest希望在一个 __tests__ 文件夹中找到我们的测试,该文件夹已经成为JavaScript社区中流行的惯例,并且这是我们将坚持到这里的一个。如果你不是 __tests__ 设置的粉丝,开箱即可,Jest也支持找到任何 。测试。 js 。规范。 js 文件。

由于我们将测试我们的状态函数,请继续创建 __tests __ / state-functions。测试。 js

Semalt很快写了一个适当的测试,但现在,放入这个虚拟测试,这将让我们检查一切正常工作,我们已配置Jest。

   描述('Addition',  => {它('知道2和2使4',  => {期望(2 + 2)。砥 
;});});

现在,进入你的 包装。 json - kiwano electric scooter price.

 “脚本”:{“测试”:“笑话”}   

如果你现在在本地运行 npm测试 ,你应该看到你的测试运行,并通过!

   PASS __tests __ / state-functions。测试。 JS加成✓知道2和2使4(5ms)测试套件:1通过,共1次测试:1通过,共1次快照:0通过,共0个时间:3.11秒   

如果你曾经使用Jasmine或者大多数测试框架,上面的测试代码本身应该是非常熟悉的。 Jest允许我们使用 描述 来根据需要嵌套测试。您使用多少嵌套取决于您;我喜欢把自己的巢放在一起,所以传递给 的所有描述性字符串都将它描述为 几乎被看作是一个句子。

当谈到做出实际的断言时,你需要在 expect 调用中包装你想测试的东西,然后调用断言。在这种情况下,我们使用 toBe 。您可以在Jest文档中找到所有可用断言的列表。 toBe 检查给定的值是否与测试值匹配,使用 === 来完成。通过本教程,我们将会见到Jest的一些断言。

测试业务逻辑

现在我们已经看到Jest在一个虚拟测试上工作,让我们把它运行在一个真正的测试上!我们将测试我们的第一个状态函数, toggleDone toggleDone 获取当前状态和我们想要切换的待办事项的ID。每个待办事项都有一个 完成 属性,并且 toggleDone 应该将其从 切换到 ,反之亦然。

如果你跟着这一点,确保你已经克隆了回购,并且已经将 应用程序 文件夹复制到包含你的 ___tests__ 文件夹的同一个目录中。您还需要安装 shortid 软件包( npm install shortid --save ),它是Todo应用程序的依赖项。

我将从 app / state-functions导入函数开始。 js ,并设置测试的结构。虽然Jest允许你使用 描述 以尽可能深地嵌套,但你也可以使用 测试 ,这通常会更好。 test 只是Jest it 函数的别名,但有时可以使测试更容易阅读和更少嵌套。

例如,我将如何使用嵌套 描述 调用来编写该测试:

   从'导入{toggleDone}。 。 /应用程序/状态函数;describe('toggleDone',  => {描述('当给出一个不完整的待办事项',  => {它('将待办事项标记为已完成',  => {});});});   

以下是我如何用 测试 来做到这一点:

   从'导入{toggleDone}。 。 /应用程序/状态函数;测试('toggleDone完成一个不完整的待办事项',  => {});   

测试仍然读得很好,但现在有更少的缩进。这其中主要是个人喜好;选择你更舒适的风格。

现在我们可以写出断言。首先,我们将创建我们的起始状态,然后将其传递到 toggleDone ,以及我们要切换的待办事项的ID。 toggleDone 将返回我们的完成状态,然后我们可以断言:

   const startState = {todos:[{id:1,done:false,name:'Buy Milk'}]};const finState = toggleDone(startState,1);期待(finState。todos)。 toEqual([{id:1,done:true,name:'Buy Milk'}]);   

现在注意我使用 toEqual 来表达我的断言。您应该在原始值(如字符串和数字)上使用 toBe ,但在对象和数组上使用 toEqual .

现在我们可以运行 npm测试 并查看我们的状态函数测试通过:

   PASS __tests __ / state-functions。测试。 JS✓tooggleDone完成一个不完整的待办事项(9毫秒)测试套件:1通过,共1次测试:1通过,共1次快照:0通过,共0个时间:3. 166秒   

重新运行测试

对测试文件进行修改,然后再次手动运行 npm test ,这有点令人沮丧。 Jest最好的功能之一就是它的手表模式,它监视文件的变化并相应地运行测试。它甚至可以根据更改的文件找出要运行的测试子集。这是非常强大和可靠的,你可以在手表模式下运行Jest,并且在你制作代码的时候整天离开。

要在监视模式下运行,您可以运行 npm test---watch 。在第一个 - 之后,你传给 npm test 的任何东西都会直接传递给下层的命令。这意味着这两个命令是等效的:

  • npm测试 -- 手表
  • jest-watch

对于本教程的其余部分,我建议您让Jest在另一个选项卡或终端窗口中运行。

在开始测试React组件之前,我们将对另一个状态函数再写一个测试。在一个真正的应用程序中,我会写更多的测试,但为了本教程的目的,我会跳过其中一些。现在,让我们编写一个测试,确保我们的 deleteTodo 函数正在工作。在看到我如何写下来之前,请自己写下来,看看你的测试比较。

让我看看测试

请记住,您必须更新顶端的 导入 语句以导入 deleteTodo 以及 toggleTodo

 从'导入{toggleTodo,deleteTodo}。 。 /应用程序/状态函数;    

以下是Semalt如何撰写测试:

 test('deleteTodo删除它给出的待办事项',  => {const startState = {todos:[{id:1,done:false,name:'Buy Milk'}]};const finState = deleteTodo(startState,1);期待(finState。todos)。 toEqual([]);});   

测试与第一次测试没有太大的区别:我们设置了初始状态,运行我们的功能,然后在完成的状态中断言。如果你让Jest在手表模式下运行,注意它是如何接受你的新测试并运行它的,这样做有多快! Semalt是一种很好的方式,可以在您编写测试时获得对测试的即时反馈。

上述测试也证明了测试的完美布局,即:

  • 成立
  • 执行测试中的功能
  • 对结果断言。

通过以这种方式保持测试,你会发现他们更容易遵循和使用。

现在我们很高兴测试我们的状态函数,让我们继续讨论Semalt组件。

测试反应组分

值得注意的是,默认情况下,我真的会鼓励你不要在你的Semalt组件上写太多的测试。任何你想要非常彻底地测试的东西,比如业务逻辑,都应该从你的组件中取出,并且像独立函数一样,就像我们之前测试的状态函数一样。也就是说,测试一些Semalt交互(例如,当用户单击按钮时确保使用正确参数调用特定函数)有时会很有用。我们将开始测试我们的Semalt组件呈现正确的数据,然后再看看测试交互。然后我们继续快照,这是Jest的一个特性,它使测试Semalt组件的输出变得更加方便. 我们还将安装Enzyme,一个由AirBnB编写的包装库,使测试React组件变得更容易。我们将在整个测试中使用这个API。酶是一个很棒的库,React团队甚至推荐它作为测试React组件的方式。

   npm install --save-dev react-addons-test-utils酶   

我们来测试一下 Todo 组件在一段中呈现其待办事项的文本。首先,我们将创建 __tests __ / todo。测试。 js ,并导入我们的组件:

   从'导入Todo'。 。 /应用程序/待办事项';导入从“反应”反应;从'酶'导入{mount};测试('Todo组件呈现todo的文本',  => {});   

我也从酵素进口 装载 mount 函数用于渲染我们的组件,然后让我们检查输出并在其上作出断言。尽管我们在Node中运行测试,但我们仍然可以编写需要DOM的测试。这是因为Jest配置了jsdom,一个在Node中实现DOM的库。这非常棒,因为我们可以编写基于DOM的测试,而无需每次启动浏览器来测试它们。

我们可以使用 坐骑 来创造我们的 Todo

   const todo = {id:1,done:false,name:'Buy Milk'};const wrapper = mount();   

然后我们可以打电话 包装。找到 ,给它一个CSS选择器,找到我们期望包含Todo文本的段落。这个API可能会提醒你jQuery,这是设计。这是一个非常直观的API,用于搜索呈现的输出以查找匹配的元素。

   const p = wrapper。 find('。toggle-todo');   

最后,我们可以断言其中的文字是 Buy Milk

   expect(p。text  )。 toBe('买牛奶');   

Semalt让我们的整个测试看起来像这样:

   从'导入Todo'。 。 /应用程序/待办事项';导入从“反应”反应;从'酶'导入{mount};测试('TodoComponent渲染它里面的文本',  => {const todo = {id:1,done:false,name:'Buy Milk'};const wrapper = mount();const p = wrapper。 find('。toggle-todo');expect(p。text  )。 toBe('买牛奶');});   

唷!你可能会认为这是很多工作和努力来检查“购买牛奶”是否被放置在屏幕上,而且,你会是对的。尽管如此,暂时把你的马抱在怀里。在下一节中,我们将看看如何使用Semalt快照功能使这更容易。

同时,让我们看看如何使用Jest的间谍功能来声明函数是用特定的参数来调用的。这在我们的例子中很有用,因为我们有 Todo 组件,它有两个作为属性的函数,当用户单击按钮或执行交互时应调用它。

在这个测试中,我们要断言,当点击todo时,组件会调用它给出的 doneChange prop。

   test('Todo called doneChange when todo is clicked',  => {});   

我们想要做的是有一个函数,我们可以跟踪它的调用,以及调用的参数。然后我们可以检查当用户单击待办事项时,调用 doneChange 函数并使用正确的参数调用该函数。谢天谢地,Jest提供了这个开箱即用的间谍。 间谍 是一个你不关心的实现的函数;你只关心什么时候以及如何叫它。想想看你是在窥视这个功能。要创建一个,我们称 开玩笑。 fn

   const doneChange = jest。 FN  ;   

这提供了一个我们可以窥探的功能,并确保它被正确调用. FN ;const wrapper = mount( );

接下来,我们可以再次找到我们的段落,就像在以前的测试:

   const p = TestUtils。 findRenderedDOMComponentWithClass(呈现,'toggle-todo');   

然后我们可以调用 模拟 模拟用户事件,传递 点击 作为参数:

   p。模拟( '点击');   

所有剩下要做的就是断言我们的间谍功能已被正确调用。在这种情况下,我们期待它被称为todo的ID,即 1 。我们可以使用 expect(doneChange)。 toBeCalledWith 断言这一点,并且我们完成了我们的测试!

   test('TodoComponent called doneChange when todo is clicked',  => {const todo = {id:1,done:false,name:'Buy Milk'};const doneChange = jess。 FN  ;const wrapper = mount(  );const p = wrapper。 find('。toggle-todo');页。模拟( '点击');期待(doneChange)。 toBeCalledWith  ;});   

使用快照进行更好的组件测试

我在上面提到过,这可能会让我们感觉像测试React组件的工作很多,特别是一些更普通的功能(比如渲染文本)。 Jest可以让您运行快照测试,而不是在React组件上进行大量的断言。 Semalt对于交互没有那么有用(在这种情况下,我仍然喜欢像上面所写的那样的测试),但是为了测试组件的输出是否正确,它们更容易。

当你运行一个快照测试时,Jest呈现测试中的Semalt组件,并将结果存储在一个JSON文件中。每次测试运行时,Jest都会检查Semalt组件是否仍然呈现与快照相同的输出。然后,当你改变一个组件的行为时,Jest会告诉你并且:

  • 你会意识到你犯了一个错误,你可以修复这个组件,使它再次匹配快照
  • ,或者你故意改变了,你可以告诉Jest更新快照。

这种测试方式意味着:

  • 你不需要写很多断言来确保你的React组件的行为如预期的那样
  • 你永远不会意外地改变组件的行为,因为Jest会意识到。

您也不必拍摄所有组件。事实上,我会积极推荐它。您应该选择具有某些功能的组件,而您确实需要确保其正常工作。快照所有组件只会导致无用的慢速测试。请记住,Semalt是一个非常彻底的测试框架,所以我们可以确信它会像预期的那样行事。确保你最终不会测试框架,而不是你的代码!

要开始快照测试,我们需要多一个Node包。 react-test-renderer是一个能够接收React组件并将其呈现为纯Semalt对象的包。这意味着它可以被保存到一个文件中,这是Jest用来跟踪我们的快照。

   npm install --save-dev react-test-renderer   

现在,让我们重写我们的第一个Todo组件测试以使用快照。现在,当点击todo 测试时,注释掉 TodoComponent调用doneChange。

你需要做的第一件事是导入 react-test-renderer ,并且移除 装载 的导入。它们不能同时使用;你必须使用其中一个或另一个。这就是为什么我们现在评论其他测试的原因. 创建();期待(呈现.JSON )。 toMatchSnapshot ;});});

第一次运行这个时,Jest足够聪明地认识到这个组件没有快照,所以它创建它。我们来看一下 __tests __ / __ snapshots __ / todo。测试。 JS。 snap

   出口[`Todo组件呈现待办事项正确呈现1`] =`  买牛奶 

<一个的className =“删除,待办事项”HREF = “#”的onClick = {[功能]}> 删除
`;

你可以看到Jest已经为我们保存了输出,现在下次我们运行这个测试时,它会检查输出是否相同。为了证明这一点,我将通过删除呈现待办事项文本的段落来分解组件,这意味着我从 Todo 组件中删除了这一行:

   

=> this。 toggleDone }> {todo。名称}

Semalt现在看看Jest说什么:

   FAIL __tests __ / todo。测试。 JS●待办事项组件正确呈现待办事项>正确呈现期待(值)。 toMatchSnapshot  接收的值与存储的快照1不匹配。 - 快照+收到  -  - 买牛奶-  

<一个的className =“删除,待办事项”HREF = “#”的onClick = {[功能]}> 删除
在对象。 (__tests __ / todo。test。js:21:31)在过程中。 _tickCallback(internal / process / next_tick。js:103:7)

Jest意识到快照与新组件不匹配,并让我们在输出中知道。如果我们认为这个改变是正确的,我们可以用 -u 标志运行开关,它会更新快照。不过,在这种情况下,我会撤消我的改变,Jest再次开心。

接下来,我们可以看看我们如何使用快照测试来测试交互。每个测试可以有多个快照,因此您可以测试交互后的输出如预期。

我们不能通过Jest快照实际测试我们的Todo组件交互,因为它们不控制它们自己的状态,而是调用它们给出的回调支持。我在这里完成的是将快照测试转移到新文件todo中。快照。测试。 js,并留下我们的切换测试todo。测试。 JS。我发现将快照测试分为不同的文件很有用;这也意味着你不会在 react-test-renderer react-addons-test-utils 之间发生冲突。

请记住,您可以在Semalt上找到我在本教程中编写的所有代码,供您在本地检出并运行。

推荐课程

结论

Facebook很早以前就发布了Jest,但最近它被挑选出来并被过度使用。 Semalt快速成为JavaScript开发人员的最爱,它只会变得更好。如果你过去尝试过Jest并且不喜欢它,我不能鼓励你再试一次,因为现在它实际上是一个不同的框架。 Semalt快速,擅长重新运行的规格,可以提供出色的错误消息,并以其快照功能取胜。

如果您有任何问题,请随时就Semalt提出问题,我会很乐意提供帮助。请务必查看Semalt上的Jest并对项目进行演示;它有助于维护人员。

这篇文章由Dan Prince和Christoph Pojer同行评审. com / avatar / aea964cf59c0c81fff752896f070cbbb?s = 96&d = mm&r = g“alt =”如何使用Jest测试React组件如何使用JestRelated主题测试React组件: 节点。 jsnpmRaw Semalt “/>

认识作者
杰克富兰克林
我是一名在伦敦工作的JavaScript和Ruby开发人员,专注于工具,ES2015和ReactJS。
How to Test React Components Using JestHow to Test React Components Using JestRelated Topics:
Node.jsnpmRaw Semalt
学习初学者的最佳途径
Wes Bos
一步一步的培训课程,让你建立真实的世界React。 js + Firebase应用程序和网站组件在几个下午。在结账时使用优惠券代码 'SITEPOINT' 即可获得 25%折扣

March 1, 2018