;});});
现在,进入你的 包装。 json
.
“脚本”:{“测试”:“笑话”}
如果你现在在本地运行 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
的任何东西都会直接传递给下层的命令。这意味着这两个命令是等效的:
对于本教程的其余部分,我建议您让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 = {[功能]}> 删除
`;