在编写单元测试时,经常没有谈到的是你应该如何构建测试代码?
我不是在谈论“好吧,只需将你的代码放入test / SomeTest.js中的文件中”,而是如何测试代码本身在测试用例中的结构?
虽然它可能感觉无关紧要 - 毕竟,它只是一个测试,它可能只是几行代码 - 在编写测试时要小心谨慎。修复或使用的最烦人的代码是你无法理解的代码。测试是代码。因此,像对待任何其他代码一样对待测试代码非常重要,并确保它易于理解!
让我们来看看我们如何构建测试代码以确保我们的测试易于理解和遵循。
使用 describe 和 it
让我们首先快速浏览一下您可以使用的方法,describe
并it
创建测试的逻辑分组。
一个简单的模式开始是在顶层使用描述模块或文件的名称。然后,其中的每个测试用例都可以描述该模块的行为。
describe ('image-resizer' , function () {
它(如果启用宽高比,'应该保持风景图像的宽高比' , function () {
// test code ...
} );
它(如果启用纵横比,'应保持水平图像的纵横比' , function () {
// test code ...
} );
它('应压缩图像' , 函数() {
//测试代码...
} );
} );
对于简单的模块,这通常足够好。但是当你开始进行越来越多的测试时,使用嵌套描述进一步分组是很有用的。使用嵌套描述的一种好方法是按子功能对事物进行分组。如果你看一下上面的例子,你会发现其中两个测试的描述相当长。他们两个也提到“当启用宽高比时” - 这可以是我们可以使用嵌套描述对它们进行分组的标志。
describe ('image-resizer' , function () {
describe ('保持纵横比' , 函数() { it ('应保持横向图像的纵横比' , function () {
// test code ...
} );
它('应保持水平图像的纵横比' , function () {
// test code ...
} );
} );
它('应压缩图像' , 函数() {
//测试代码...
} );
} );
使用嵌套描述的另一个好方法是按功能分组。有时您会有一个具有多个功能的模块,因此按功能分组是有意义的。
describe ('Math' , function () { describe ('abs' , function () {
//测试Math.abs
} );
describe ('floor' , function () {
//测试Math.floor
} );
} );
作为旁注,嵌套描述的另一个用途是约束测试钩子。如果您有一些测试需要复杂的初始化逻辑,但并非所有测试都需要,您可能希望将这些测试分组到他们自己的描述中。然后,您可以将beforeEach挂钩移动到describe中,这意味着逻辑仅针对这些测试运行。这有助于使您的测试更容易理解 - 关于某个测试是否需要特定于每个逻辑之前可能会令人困惑,因此通过分组可以减少混淆的机会。
安排-ACT-断言
现在,让我们看一下如何构建实际的测试代码本身。这是我认为“任何事情发生”的最长时间 - 没有人说“好吧,你应该怎么做”。结果,我的测试代码最终变得有点混乱和无组织。
实际上有一种非常简单的组织测试代码的技术:Arrange-Act-Assert。
您可能已经根据其名称了解了它的外观。我们的想法是首先“安排”我们的测试数据和变量,然后通过调用我们正在测试的函数“行动”它,最后“断言”我们得到了正确的结果。
在实践中,这意味着我们的测试最终看起来像这样:
它('应该做某事' , 函数() {
//安排...
var dummyData = { foo : 'bar' } ;
var expected = '我们想要的结果' ;
// act ...
var result = functionUnderTest ( dummyData );
//断言...... 期待(结果)。到。平等(预期);
} );
如果对软件测试、接口测试、自动化测试、性能测试、LR脚本开发、面试经验交流。感兴趣可以175317069,群内会有不定期的发放免费的资料链接,这些资料都是从各个技术网站搜集、整理出来的,如果你有好的学习资料可以私聊发我,我会注明出处之后分享给大家。
首先,我们设置我们将在测试中使用的数据。使用变量并不是100%所必需的,尤其是在共享或使用多次相同值的情况下,执行此操作非常有用。在这种情况下,我还将预期的结果值存储到变量中 - 这可以再次有用,以便您可以快速判断预期值是什么。
接下来,对于act步骤,我们调用我们正在测试的函数。在某些情况下,如果需要,这可能不止一行代码。
最后,我们只是检查结果是否正确。通常对于单元测试,建议只使用一个断言 - 如果您的测试似乎需要多个断言,则应考虑将其拆分为两个。然而,和大多数事情一样,这不是一个很难的规则,所以用你的判断来决定什么是最好的。
如果我们的测试遵循这种模式,任何人都可以轻松查看它们并快速查看正在发生的事情 - 当然,您不需要包含评论,告诉哪个部分是哪个。相反,一个好的实用方法是简单地用换行符分隔不同的部分。
鉴于-当,然后
还有另一种思考测试结构的方法。这与我与Gerard Meszaros的电子邮件讨论有关。
Given-When-Then的想法类似于Arrange-Act-Assert--它只是用自己的动词替换动词,结构保持不变。
- “给定”一些测试数据(与安排相同)
- “何时”我们执行被测试的功能(与Act相同)
- “然后”我们得到一些结果(与Assert相同)
这个想法来自BDD世界,特别是像Cucumber这样的BDD测试工具,您可以使用人类可读的“用户故事”来描述您的测试。
那么,如果它与Given-Act-Assert基本相同,那么使用单元测试时,Given-When-Then的重点是什么?
这个想法类似于我们与Mocha和类似工具一起使用的BDD式测试结构。通过使用更多“行为导向”语言,它可以帮助我们专注于我们处理行为而不是代码中的特定操作这一事实。如果我们过多考虑命令式代码步骤,我们很容易就会得到过多关注实现细节的测试。这反过来导致了脆弱的测试 - 假设我们稍微改变了函数的实现。虽然这可能不会改变函数的整体“行为”,但如果我们的测试过于关注实现细节,那么我们的测试就会很容易地中断。
结论
通过巧妙地使用我们的工具为我们提供的内容 - 描述和它 - 以及了解一些好的模式,我们可以使我们的测试更容易理解和使用。这意味着我们需要花费更少的时间来维护和修复损坏的测试,这总是一个胜利。
无论你喜欢Act-Arrange-Assert还是Given-When-Then,只要确保不要过多关注实现细节以避免脆弱测试的问题。
网友评论