如何编写出色的单元测试(入门指南)
介绍:
本教程旨在帮助您入门测试,特别是单元测试。在本教程中,我们将学习如何为 Vue.js 应用设置单元测试。市面上有很多测试框架,相信您一定听说过其中不少。我们将使用 Jest 框架进行测试。我们会使用 vue-test-utils,它能简化测试的编写。我们还会用到一些其他工具,但在这个阶段不必过于关注它们。
你将学到什么:
在本教程结束时,您将掌握为 Vue 应用设置单元测试的实用知识。虽然我们将设置的测试比较基础,但我也会告诉您如何查阅文档并设置更复杂的测试。您将能够立即运用本教程中学到的技能。让我们开始吧。
先决条件:
由于你要为 Vue 应用编写测试,因此我们假设你已经对 Vue.js 框架有一定的了解。除了测试本身之外,我们还会修改 package.json 和 .babelrc 文件。你无需了解这些文件的全部内容以及我们将要写入其中的具体代码,只需知道它们的作用即可。
创建 Vue 项目:
首先,我们将使用 webpack 模板创建一个简单的 Vue 项目。虽然 Vue 3.0 版本引入了另一种创建项目的方式,无需使用模板,但由于我经常使用模板,所以本教程中也将继续使用模板。两种方式创建的项目并没有太大区别。
您可以根据需要选择这些值——项目名称、描述和作者。我个人更喜欢使用独立构建(运行时+编译器),但您也可以选择其他方式。这是一个示例项目,旨在帮助您学习测试,因此无需路由。您可以选择代码检查工具,但无需设置单元测试和端到端测试选项。
如果您不清楚应该选择哪些选项,可以参考上面的图片,并根据需要进行一些必要的更改。但是,请不要设置测试,因为我们会自行设置。由于这不是 Vue 教程,您需要自行完成项目安装的后续步骤。
这是一个简单的模板,我们将对其进行测试。您可以根据需要修改文本,但请保持整体结构不变(两个按钮——一个用于更改数据属性,另一个用于调用函数)。
安装测试依赖项:
现在我们的项目已经启动并运行,是时候安装设置单元测试所需的所有实用程序和软件包了。
简单解释一下我们安装的这些新软件包:
- vue-jest:我们将在一个 JavaScript 文件中设置测试。这个包会将我们的 Vue 文件解析/编译成简单的 JavaScript 代码,方便后续使用。
- babel-jest:这个包可以帮助我们处理一些前沿语法。如果我们使用的语法和特性尚未被广泛支持,并且需要编译,那么这个包可以让 Jest 和 Babel 协同工作。
- jest:这是实际 Jest 设置的软件包
- @vue /test-utils:创建组件实例需要此包。
请务必使用 `--save-dev` 标志。这一点至关重要。因为所有这些软件包都应该仅处于开发模式,而不是生产模式,用户并不需要它们。如果我们从生产环境中排除这些软件包,就可以减轻项目的重量。
现在,我们要修改之前提到的配置文件。这些修改将应用到 Vue.js 在创建项目时自动生成的 package.json 和 .babelrc 文件中。package.json 包含了项目的所有依赖项,而 .babelrc 是 Babel 所需的配置文件。Babel 非常强大,它可以将我们新的 JavaScript 代码转换为旧版浏览器也能理解的格式。
所有改动都在注释中进行了说明。由于我们的目标是尽快开始编写测试,因此我不会详细介绍这些改动。
写作测试:
项目已创建,所有依赖项均已成功安装,所有设置均已完成。现在我们可以开始编写一些精彩的测试了!
在我们的 Vue.js 应用中,有一个数据属性可以通过点击按钮来切换,另一个按钮会调用一个函数,该函数会向控制台打印一条简单的消息。我们将在测试中点击这些按钮(是不是很棒!),检查数据属性是否被切换,然后再检查函数是否被调用。
在 Jest 中,测试的工作方式是这样的:我们可以运行一些代码,然后告诉 Jest 我们“期望”得到一些输出/结果,并让它将我们的期望与实际结果进行比较。我们可以期望某个值被改变、某个函数被调用,甚至期望某个函数的返回值。我们可以让 Jest 检查任何内容(当然,要有一定的限制)。让我们编写第一个测试:
在根目录下创建一个名为 tests 的新文件夹。如果您不熟悉根目录这个概念(我知道我一开始也很困惑),您的文件夹结构应该如下所示:
这个目录将包含你所有的测试文件。测试文件的名称必须与被测文件的名称相同,并且需要在两者之间加上`.test`扩展名。例如,如果你要为`index.js`编写测试,那么测试文件名将是`index.test.js`。如果你要测试`HelloWorld.vue`,那么测试文件名将是`HelloWorld.test.js`。我们的文件是一个普通的 JavaScript 文件,因此扩展名为`.js`。由于我们要为 ` Test.vue`组件编写测试,因此我们将相应地命名文件(`Test.test.js`)。正如我上面提到的,Jest 通过将实际结果与预期结果进行比较来测试我们的代码。但是,它只允许我们编写一个测试。
不用担心,我们可以编写更多测试用例。测试用例包含在一个叫做测试套件的东西里。
你可以把测试套件想象成一盒甜甜圈。它可以装很多甜甜圈,足够我们吃(先别吃,我们得先工作!)。但问题是,每个甜甜圈只能有一种口味。它可以是巧克力味,也可以是草莓味,但你不能两种都吃。所以,一个简单的解决方法——你可以在盒子里放两个甜甜圈:一个巧克力味,一个草莓味。这样你就可以随心所欲地选择口味了:)。
同样,对于我们的测试,尽管我们只能告诉 Jest 每个测试预期一个结果,但我们可以在同一个测试套件中编写多个测试。让我们一步一步来;首先,我们点击第一个按钮,检查数据属性是否已更新。
大部分解释都写在评论里了。所以我只解释一些比较难懂的地方:
关键字`describe`就是我之前提到的测试套件(甜甜圈框)。它包含测试用例。测试套件和测试用例的结构由我们自己决定。在这个例子中,由于只有一个组件需要测试,所以我们只有一个测试套件。我们将编写两个测试用例来测试两个按钮。`it`是另一个用于编写单元测试的关键字。它接受两个参数。第一个参数是一个字符串,即测试用例的名称。名称通常应该具有指示性,例如,如果测试是检查链接是否有效,那么将其命名为像“测试 1”这样通用的名称就显得不够直观。第二个参数是一个包含测试逻辑的函数。在前面的代码行中,我们已经挂载了组件。现在我们可以自由地使用组件实例了。测试的第一行设置了实例的 `data` 属性(记住:组件实例与原始组件完全相同,只是结构不同。我们需要补充所有数据和函数)。现在我们已经设置了数据属性,下一行代码会使用按钮的 ID 找到与该数据属性关联的按钮。它会在组件模板中查找该按钮,然后模拟点击操作。此时,数据属性应该处于切换状态。为了验证这一点,我们可以告诉 Jest 我们期望数据属性发生变化。测试用例的最后一行代码实现了这一点。我们期望数据属性的内容为某个值。这可以通过 Jest 提供的 ` toBe(我们期望的值)`方法来实现。Jest 将运行测试,并将结果与我们的期望结果进行比较。请注意 `expect` 内部的参数——`wrapper`是组件实例,`vm`类似于我们使用`this`关键字的方式,而`content`是我们的数据属性。
现在我们来运行测试:
测试结果提供了大量信息,这对我们编写多个测试用例很有帮助。
太棒了!你刚刚完成了第一次测试。为了庆祝一下,吃个甜甜圈吧 :)
现在我们将编写下一个也是最后一个测试,以检查第二个按钮是否成功调用了某个方法。
大部分命令你应该在第一个测试中已经熟悉了。我会解释一些新的命令。在这个测试用例中,我们将检查按钮点击后是否调用了一个函数。我们需要做类似第一个测试用例中设置数据属性的操作。在这里,我们需要设置一个方法。此时,我们并不关心方法内部发生了什么,我们只关心它是否被调用。虽然我们可以创建一个空方法,但最好是模拟一个方法(创建一个假的方法)。然后,我们将这个假方法赋值给实际方法的名称。这样做的好处是,当调用实际方法时,Jest 会识别到 ` setMethods()`函数并调用我们的模拟方法。之后,我们像之前一样,找到按钮,模拟点击,然后使用 Jest 测试我们期望的结果。在这个例子中,我们期望调用的是一个函数,所以我们使用了与之前不同的 Jest 内置方法。
测试失败怎么办?
我先解释一下测试失败时会发生什么。现在对测试做一些修改。比如,把预期数据属性为 `<data>` 的那一行false改成 `<data> true`。别担心,这不会造成太大影响。现在用同样的命令再次运行测试。你应该会看到类似这样的结果:
你可能已经注意到,当所有测试都通过时,会显示一条简单的消息。但当一个测试失败时,就会出现一大堆代码,到处都是红色的警告线。它们似乎在指责你,告诉你哪里做错了。但别担心。这些红色警告是测试的重要组成部分。在最初的几行代码中,你可能会看到第一个测试的名称旁边有一个叉号。这表示哪个测试出了问题。再过几行,它会显示预期结果和实际结果。这对我们来说非常有帮助。我们可以一眼看出区别。实际结果是 `<value>`,false而我们告诉 Jest 预期的结果是 `<value>` true。不仅如此,紧接着的下一行代码会被指出,这样我们就不用费力去查找问题了。就是这样;所有这些吓人的红色警告线都不必让你担心。相反,它们能极大地帮助我们找到问题所在。
以上只是一些基础测试。那么,如何编写更复杂的测试呢?要写些什么?从哪里开始?什么时候写什么?
一个简单的答案是去谷歌或 Stack Overflow 上搜索答案,或者在网上搜索相关文章。但这并不能帮助你提升技能。如果你想让你的甜甜圈盒里装着最好的甜甜圈,你需要付出努力。首先,你需要明确你需要测试什么。你需要检查数据属性的值吗?你想触发按钮、单选按钮还是选中复选框?你想确保某个函数被调用?还是想检查它被调用了多少次?这一切都取决于你想测试什么。去看看Jest 的文档,花些时间浏览一下各种方法。它们的名称通常都很直观。多做尝试和纠错。这样你才能编写出优秀的测试。
在撰写本文之前,我经历了一番摸索。最初,我按照Medium上的这篇教程进行操作。但是,当我查看 Jest 的文档和 vue-test-utils 的 GitHub 页面时,发现两者之间存在一些冲突(可能是因为自作者撰写文章以来,这两个包都发生了一些变化);此外,作者对组件的 HTML 部分(模板)进行了大量测试,而我想要测试的是脚本逻辑。因此,我不得不进行一些实验。我撰写本文是为了解释我的发现以及我是如何编写我的第一个测试的。所以,请继续尝试。如果你遇到困难,总会有很好的资源可以帮助你。顺便说一句,我链接的 Medium 文章对于测试模板也很有帮助,可以去看看。另外,这里还有一篇关于测试 Vue.js 组件的更深入、更全面的文章。
就这样!你刚刚为你的 Vue.js 应用编写了一些很棒的测试。感觉如何?如果你有任何问题,请在下方评论区留言。我很乐意收到你的反馈。
文章来源:https://dev.to/napoleon039/a-guide-to-writing-awesome-unit-tests-for-the-first-time-2lb9