paint-brush
Vue Amsterdam 2022 - 第六部分:这是一个(测试)陷阱!经过@mohsenv
161 讀數

Vue Amsterdam 2022 - 第六部分:这是一个(测试)陷阱!

经过 Mohsen Vaziri8m2022/07/13
Read on Terminal Reader
Read this story w/o Javascript

太長; 讀書

这是我的 Vuejs 阿姆斯特丹会议 2022 总结系列的第六部分。会谈于 6 月 1 日至 3 日在阿姆斯特丹剧院举行。

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Vue Amsterdam 2022 - 第六部分:这是一个(测试)陷阱!
Mohsen Vaziri HackerNoon profile picture


欢迎!很高兴在我的 Vuejs 阿姆斯特丹会议 2022 总结系列的第六部分见到你,我在其中与你分享所有谈话的总结。


你可以在这里阅读我的 JSWorld Conference 2022 总结系列(分为四个部分),我总结了第一天的所有演讲。您还可以在我的博客中找到 2022 年 Vue 阿姆斯特丹会议之前的演讲。

(经常性)介绍

两年半之后,JSWorld 和 Vue 阿姆斯特丹会议于 6 月 1 日至 3 日再次在阿姆斯特丹剧院举行,这是我第一次有机会参加这个会议。我学到了很多东西,遇到了很多很棒的人,与优秀的开发人员交谈,度过了愉快的时光。第一天举行了 JSWorld 会议,第二天和第三天举行了 Vue Amsterdam。


会议充满了信息,有很多很棒的演讲者,他们每个人都教会了我一些有价值的东西。他们都想与其他开发人员分享他们的知识和信息。所以我想如果我能继续分享它并帮助其他人使用它会很棒。


起初,我尝试分享一些笔记或幻灯片,但我觉得还不够好,至少不如演讲者与我分享的那么好。所以我决定重新观看每一次演讲,深入了解他们,搜索,做笔记并将它们与他们的幻灯片甚至他们演讲中的确切单词结合起来,然后与你分享,这样我与你分享的内容至少是与我从他们那里学到的水平相同。

非常重要的一点

你在这几篇文章中读到的一切都是演讲者自己努力和时间的结果,我只是试图学习它们,以便将它们变成这些文章。甚至这些文章中写的许多句子正是他们所说的或他们在幻灯片中写的。这意味着如果你学到了新东西,那是因为他们的努力。 (所以如果你看到一些错误信息责怪他们,而不是我,对吧?xD)


最后但并非最不重要的一点是,我可能不会在一些演讲中深入研究每一个技术细节或实时编码。但是如果您有兴趣并需要更多信息,请告诉我,我会尝试单独写一篇更详细的文章。另外,不要忘记查看他们的 Twitter/Linkedin。


在这里您可以找到会议的程序。



这是一个(测试)陷阱!常见的测试陷阱以及如何解决它们


Ramona Schwering - shopware 的软件开发人员


“这是一个陷阱”——一个我们都可能熟悉的电话或感觉,不仅在《星球大战》中。它标志着一个突然注意到迫在眉睫的危险的时刻。


这种情况是测试中令人不快的实现的一个很好的寓言。想象一下,在测试方面有最好的意图,但最终测试仍然无法为您带来任何价值?


那些感觉很痛苦的测试?


在编写前端测试时,会有很多陷阱。总之,它们会导致糟糕的可维护性、缓慢的执行时间,以及——在最坏的情况下——你无法信任的测试。


但最糟糕的痛点是那些给你新价值和结果的测试,因为它们是片状的。您的构建有时会通过,有时会失败,而您之间什么也没做。

痛点

您可能确信测试有很多好处和优势,但所有这些美妙的事情都可能被各种原因引起的痛点所掩盖。你做的所有事情都是出于好意,但从长远来看,甚至更早,结果都变得痛苦或疲惫。


例如,缓慢的测试会扼杀乐趣。想象一下,您有您的拉取请求并且您希望它被合并,但是您需要等待数小时甚至数天才能最终完成管道。


更糟糕的是维护起来很痛苦的测试。你回想过去的自己,然后问:你用这个测试做了什么?目的是什么?!你怎么看那个?或者其他团队成员向您询问有关您过去所做的事情而您不知道的问题。


但最糟糕的痛点是那些给你新价值和结果的测试,因为它们是片状的。您的构建有时会通过,有时会失败,而您之间什么也没做。

简单测试

它不必是这样的。 JavaScript 测试最佳实践中最重要的心态和黄金法则之一是简单。


在每种情况下,测试都应该设计得简单明了。在单元测试、集成测试和端到端测试中,保持简单。


我们的目标应该是能够理解您的测试并立即获得其意图而无需考虑它。


尝试以扁平化测试设计为目标,这意味着只进行所需的测试,并且几乎不使用抽象。

陷阱

让我们看看第一个Trap。


 describe('deprecated.plugin', () => { it('should throw error',() => { … }); });


如果已弃用的插件正在使用中,它应该会抛出错误。

当你看标题时——应该抛出一个错误——你不知道它想要完成什么。但是黄金法则说你应该立即知道它在做什么。


我们可以通过“三部分规则”使其更易于理解。测试标题应该包含三件事:

  1. 正在测试什么
  2. 什么情况下应该测试
  3. 预期的结果是什么


牢记这条规则,我们的测试将如下所示:


 describe('deprecated.plugin', () => { it('Property: Should throw an errorif the deprecated prop is used', () => { … }); });


下一个 Trap 可以是测试结构:


 describe('Context menu', () => { it('should open the context menu on click', async () => { const wrapper = createWrapper(); expect(wrapper.vm).toBeTruthy(); await wrapper.trigger('click'); const selector = '.sw-context-menu'; expect(wrapper.find(selector).isVisible()).toBeTruthy(); }); });


在这种情况下,声明、动作和断言被写在所有地方,没有任何清晰的结构。尤其是在更大的测试中,这可能是一个巨大的痛苦。我们可以使用 AAA 模式使其更加结构化。您将测试分为三个部分:


  1. 安排:与测试旨在模拟的场景的设置有关的所有内容。
  2. 行动:在测试中运行您的单元并执行步骤以达到结果状态。
  3. 断言:您可以在哪里进行断言并检查您的测试场景。


这是我们使用 AAA 模式进行的测试:


 describe('Context menu', () => { it('should open the context menu on click', () => { // Arrange const wrapper = createWrapper(); const selector = '.sw-context-menu'; // Act await wrapper.trigger('click'); // Assert expect(wrapper.vm).toBeTruthy(); expect(wrapper.find(selector).isVisible()).toBeTruthy(); }); });


这看起来好多了!


但有一个问题。回想一下我们的测试用例。它是一个上下文菜单,默认情况下是隐藏的。所以我们需要打开它来与之交互。但这意味着我们需要做一个断言来确保它在行动之前是开放的。它不会破坏模式吗?


如果我们正在测试 DOM,我们有时需要检查之前和之后的状态。那么让我们从另一个角度来看看这个模式。

  • …安排我的测试 == 我得到了什么。
  • …在我的测试中采取行动 ==有事情发生时。
  • …断言结果==发生了一些事情,然后这就是我所期望的结果。


这是一种取自行为驱动开发的模式:Given - When - Then


我们之前使用此模式的测试:


 describe('Context menu', () => { it('should open the context menu on click', () => { // Given const contextButtonSelector = 'sw-context-button'; const contextMenuSelector = '.sw-context-menu'; // When let contextMenu = wrapper.find(contextMenuSelector); expect(contextMenu.isVisible()).toBe(false); const contextButton = wrapper.find(contextButtonSelector); await contextButton.trigger('click'); // Then contextMenu = wrapper.find(contextMenuSelector); expect(contextMenu.isVisible()).toBe(true); }); });

端到端测试

避免使用占位符,尽可能使用真实的命名。


 it('should create and read product', () => { … cy.get('.sw-field—product-name').type('T-Shirt Ackbar'); cy.get('.sw-select-product__select_manufacturer') .type('Space Company'); … });


如果你不想想出成千上万个名字,也许你可以使用 faker 或其他工具来生成一些虚拟数据,或者如果法律和你的项目没问题,从生产状态导入。只需确保您的测试易于理解且易于阅读,并且您知道它的作用。


让我们看看下一个陷阱的相同测试,即选择器。


如果你重构你的应用程序并更改一些类——这很常见——这可能会导致你的测试失败,在这种情况下,测试失败而你的应用程序中没有出现错误——这被称为假阴性,无法提供可靠的报告应用程序,因为它没有损坏,只是您的实现发生了变化。


看看你必须的选择器!换句话说,您不应该测试实现细节。相反,请考虑使用用户会引起注意的事物并导航您的应用程序。例如页面内的一些文本。更好的是,使用不易更改的选择器,例如数据属性。例如,您甚至可以将其称为 cypress data-cy=”submit” ,以便立即知道它是用于测试的。


最后但同样重要的是,不要使用固定的等待时间。


 Cypress.Commands.add('typeSingleSelect', { prevSubject: 'element', }, (subject, value, selector) => { … cy.wait(500); cy.get(`${selector} input`) .type(value); });


一方面,如果一个测试用例会被执行很多次,这会大大减慢你的测试速度。当您的应用程序在较弱的硬件上使用时,情况可能会更糟。在这种情况下,您可能需要超过 500 毫秒的修复时间。


有一些解决方案,例如等待 UI 中的更改,例如加载微调器消失或动画停止或出现某些内容。

或者更好的是,等待 API 请求和响应。


测试是你的助手,而不是障碍。他们应该感觉像是例行公事,而不是解决复杂的数学公式。



第六次谈话结束

我希望你喜欢这部分,它对你和对我一样有价值。在接下来的几天里,我将与你分享剩下的谈话。敬请关注…


也在这里发布。