软件开发公司的全栈测试:平衡单元测试和端到端测试

软件开发公司的全栈测试:平衡单元测试和端到端测试

* 来源: * 作者: * 发表时间: 2020-09-30 0:10:01 * 浏览: 0
软件开发公司的全栈测试:平衡的单元测试和端到端测试全栈开发人员的特点是能够从头到尾交付和发布功能。教程和书籍通常侧重于建立全栈开发环境和测试所需的管道(我将Angular,Rails,Bootstrap和Postgres结合使用)。但是,通常缺少有关如何在整个Web开发堆栈中测试应用程序的指导。让我们深入研究本文。我们将学习如何充分利用端到端测试,包括有关测试内容以及如何确保这些测试的可靠性和可维护性的指南。我们还将讨论单元测试及其在端到端测试策略中的作用。但是首先,我们需要了解编写测试的基本目的。从根本上说,测试是为了确保应用程序的行为符合开发人员的意愿。它们是执行代码并检查其行为是否符合预期的自动化脚本。测试编写得越好,您就越可以依靠它们来保护部署。如果测试还不够,则需要QA团队或发布有缺陷的软件(这都意味着用户获得价值的速度比理想情况要慢得多)。如果测试足够,则可以放心,快速地发布,而无需批准或进行质量检查等缓慢的手动过程。对于笔试,我们还必须权衡未来的可维护性。应用程序将更改,因此测试也将更改。在理想情况下,测试的修改与软件的修改成正比。如果您修改错误消息,则您不想大量重写测试套件。但是,如果您完全修改了用户流程,则可以预期将重写许多测试。实际上,这意味着您不能将所有测试都视为端到端的综合集成测试,而不能仅仅执行性能较差的单元测试。关于如何实现这种平衡。测试类型测试类型很多,但是在本文中,我们将讨论两种类型:端到端测试和单元测试。端到端测试可模拟用户行为。在Web应用程序中,他们将启动服务器,打开浏览器,单击任意位置,断言浏览器中发生了特定的事情,并使我们相信该功能正常运行。这些测试将使我们充满信心,但它们缓慢而脆弱,并且与用户界面紧密相关。单元测试根据代码单元的公共API运行它们。这些测试需要创建一个类的实例,使用特定的输入调用其方法,并断言所调用的方法已达到预期的效果(通常返回预期的输出)。这些测试快速,稳定,并且与系统的其他部分紧密耦合。但是,他们不能说服整个系统可以运行mdash,mdash,但是经过测试的代码单元可以正常运行。构建功能的任务是在两种类型的测试之间找到适当的平衡。如果端到端测试太多,那么将来对应用程序的更改将是痛苦而缓慢的。如果数量太少,那么即使快速测试套件的代码覆盖率为100%,也会有一些无法察觉的缺陷会进入生产环境。从用户体验入手您的软件是为特定用户提供服务,以便该用户推动您的工作。我不建议使用测试来设计用户体验,因此请在编写测试之前(通过实验代码或与设计师合作)弄清楚用户将如何使用该软件。一旦弄清楚,就可以开始工作了。理想情况下,您将为用户体验的特定部分创建端到端测试,并编写代码以通过测试。在编写这些代码时,您将创建用于指定需要创建或修改的代码规范的单元测试(通常是后者)。问题在于,如果没有要引用的用户界面工件(HTML),就很难编写端到端的故障测试。这是因为大多数端到端测试都采用以下形式:在页面上找到一个元素,in以某种方式与之交互,确认交互成功,重复上述过程直到测试结束。这意味着您需要围绕将要交互的用户界面元素(DOM对象)制定一些规范。当扭角羚g考虑到基于JavaScript的交互设计,如果不实际构建接口,至少要进行部分测试,则很难进行测试。为此,必须在浏览器中运行粗略的UI大纲。使用预先准备的数据,无需考虑替代过程mdash,mdash,一次只关注一件事情。运行后,您可以编写测试。在执行此操作时,需要考虑两点:是否需要测试此功能?如果是这样,如何测试呢?测试内容尽管编程中没有令人愉悦的路径,但是用户体验的代码路径远少于可能的代码路径。例如,当用户购买产品时,我们可能会根据用户的地址,选择的送货方式或以前的购买历史记录以不同的方式处理订单。在所有情况下,用户体验都是相同的,因此在用户看来,只有一个过程。目前,您的目标是测试所有用户流。您需要一个测试套件来模拟用户执行您想要和想要的操作,并断言您要提供给用户的所有体验均在正常运行。如果您已经知道要测试什么,应该如何进行?如何执行端到端测试如果修改流程,则必须修改该流程的测试。由于端到端测试模拟了用户活动,因此无需为要声明的所有内容编写测试。如果用户应该在结帐界面上看到三条重要信息,则无需编写三个测试mdash,mdash,而一个测试就足以检查所有三条信息。因此,在修改现有用户体验时,请寻找可以改进的现有测试。否则,需要新的测试。请记住,您的目标是模拟用户必须执行的操作。诚实对待测试中如何组织导航和行为很重要。用户实际上会直接导航到某些深层链接吗?还是他们会单击公共开始页面到达所需的位置?这很难做到,尤其是因为通常使用较少的标签来实现此功能。测试需要找到要与之交互的特定DOM元素,而准确地找到要与之交互的元素并不总是那么容易(或不可能)。您需要ldquo,路标。徽标专门插入到DOM中以找到感兴趣的元素。有必要尽早确定这些迹象将如何发挥作用。最初用于样式设置的CSS类不应用于定位DOM元素。这样做意味着前端开发人员更改类名并破坏测试。您也不应使用CSS类或JavaScript代码使用的数据属性(例如以js-开头的类)。这将带来相同的损害。使用以test-为前缀的CSS类或以data-test-为前缀的属性是两种常见的技术:hell这似乎令人不舒服hellip,hellip确实如此。但是,这比将测试耦合到内容或表示类要麻烦得多。在这里,您需要在mdash和mdash之间寻求平衡,并且不要盲目地使用data-test属性标记每个元素。例如,如果您想单击某个按钮来购买特定产品,那么您真正需要做的就是找到一个包含该产品和“购买”按钮的元素。添加data-test-product属性后,您可以使用CSS选择器,例如[data-test-product = 39,123439,] input [type = 39,submit39,]找到产品1234的购买按钮。button这意味着您必须修改仅用于测试的标记,即,为了获得您提供给他们的用户体验,用户需要下载一些不需要的字节。这是一个平衡,但比差的测试覆盖率要好(对用户的危害远远超过HTML中多余的字节)。它必须是正确的。当页面上发生交互而无需重新加载即可更改页面内容的情况下(换句话说,使用JavaScript),此技术就显得尤为重要。处理交互每次单击重新加载页面时,端到端测试更加可靠,因为底层工具知道等待页面重新加载。当用户交互仅用于更改DOM时,将更加困难,因为该工具不知道发生了什么,因此无法等待它完成。当测试需要与不会根据用户操作重新加载的页面进行交互时,它需要一种方法来在开始断言发生的事情之前,请等待DOM操作完成。如果您不等待,则如果在测试开始声明时尚未更新DOM,则测试将不必要地失败。就像使用标记来定位要操作的DOM元素一样,我们也可以在此处使用它们。任何新的或更改的标记都应具有某种标记,如果交互失败或没有发生,则该标记将不会出现。换句话说,您不必为了等待DOM事件而在测试中调用mdash,即mdash,DOM应该包含用于测试显式等待的标志。例如,假设我们要测试某个动作为用户生成了一条成功消息。假设实现方法是发出AJAX请求,并在调用结束时在DOM中插入一条消息。基本的实现可以像这样完成:functionpurchase(productId){$ .post(quot,/ products / quot ,, {“ id,id :: productId}).done(function(){$(”。header“,) .Html(quot,Yourorder已放置quot,),})。fail(function(){$(“ ,. headerquot,)。html(quot,Therewasaproblemquot,)可用于测试,Therewasaproblemquot,)CSS警报的元素-成功出现,并声明其内容。这意味着如果页面需要使用该类的任何其他元素,则测试将不可靠或损坏。尽管您可以将其限制为HTML标头,但这只是一个缓慢的过程。或者,您可以使用数据测试属性:functionpurchase(productId){$ .post(quot,/ products / quot ,, {“ idid,:productId}).done(function(){$(quot) ,.headerquot,)。Html(quot,Yourorderplaced quot,),})。fail(function(){$(quot,.headerquot,)。html(quot,Therewasaprobquot,Bytes,Therewasaprobquot,),但是它允许您编写不受某些视觉变化影响的可靠测试。只要成功购买后页面流显示一条消息,就可以修改可视化实现,而不会破坏测试。这就是您想要的,这是一个折衷。您也可以牺牲这种信心并创建更小,更基本的标记,但是当显示效果发生变化时,您将花费时间修复测试,被迫手动进行质量检查或发布尚未经过全面测试的软件。当今的端到端测试工具(如Capybara)包含您需要的所有功能。它提供了在继续测试过程之前等待DOM元素出现,断言页面特定部分的内容以及与表单元素进行交互的方法。大多数其他Web应用程序堆栈都提供类似的工具。无论哪种方式,您都可以将测试库与非接口浏览器(如PhantomJS)结合使用,以实现出乎意料的快速和可靠的端到端测试。另一个值得注意的地方是如何在分布式环境中完成这项工作。当ldquo时,有多个应用程序测试单个整体系统时,上述技术完全足够。但是,如果测试的是分布式系统,则情况会更加复杂。假设您正在处理面向客户的应用程序,但是它必须从另一个系统获取库存数据。您如何为此编写测试?首先,请记住您要测试的内容。端到端测试是测试用户交互。这意味着端到端测试不负责声明远程服务的功能,也不负责声明应用程序正确使用了该远程服务。检验服务消费的最佳方法是使用ldquo,这是一种由消费者驱动的合同(由消费者驱动的合同),这是单元测试的一种形式(至少在我在本博文中所做的广义定义中)。关于如何在端到端测试中模拟远程服务,仍然没有结论。您可以构建服务的实际版本,但这不是很好。您最终必须管理该服务及其依赖的服务的内部数据存储。这将迅速增加复杂性并使其难以管理。常见的选择是使用HTTP层仿真系统。在Ruby中,VCR是具有此功能的工具。您记录与真实服务进行交互以建立HTTP协议往返的过程。稍后运行测试时,模拟系统将在不使用网络的情况下重播记录的交互。如果单元测试涵盖了正确的服务使用,则这对于端到端测试有效。另一个o解决方案是构建一个简化的模拟服务,以返回预先准备的数据。该应用程序将照常进行HTTP调用,但会调用预先准备的服务,并且仅将静态已知数据返回给该应用程序。这需要事先进行一些配置,但是对于简单的服务交互而言是有效的。如果应用程序需要在服务中存储状态,并且有很长的往返对话,那么此技术将更加困难。我的建议是尝试首先模拟HTTP,因为它既简单又快速。现在,我们知道在端到端测试中要测试什么以及如何测试,那么单元测试又如何呢?单元测试回想一下,对于应该进行的端到端测试,我们的标准是用户流程。这个想法是,尽管整个系统中存在许多可能的逻辑过程,但对用户体验的影响却要少得多。单元测试是测试其余逻辑流程。这使我们能够快速,可靠地断言系统大多数功能的正确行为。换句话说,尽管我们可以使用端到端测试来断言整个系统中的每个可能过程,但这不是必需的,并且会非常缓慢且脆弱。例如,假设有两个用于结算功能的用户流程:一个是成功购买,另一个是失败购买。用户必须重试。将有两个端到端测试。让我们进一步假设后端存在以下可能性:客户的信用卡已正确借记,with与客户银行的通信存在问题,但我们要假装成功,然后再借记,客户的客户的信用卡已过期。这是四个过程,因此我们希望有四个单元测试可以断言它们每个均已正确处理。是的,将有重复的承保范围。在端到端测试中,我们可以创建两个用户流程来成功扣除和拒绝两个测试以处理此功能。因此,编写单元测试时,我们的研究范围将超出理论需求。同样,这是一个折衷,但是重要的是单元测试可以很好地覆盖您的类。这使他们可以更改其位置,目的和更轻松的修改。关于如何编写单元测试的理论很多,这超出了我们在此讨论的范围。我的建议是采用一种对您有用并且易于向他人解释的技术,并一直使用它。对于单元测试,最困难的部分是确定测试应考虑多少代码设计。这类似于我们向HTML添加属性和其他标识符mdash和mdash进行测试的方式。这些工件仅存在是因为我们要测试。在编写单元测试时,您面临相同的选择。例如,假设“购买者”类实现了信用卡借方代码。假设它将使用第三方提供的AwesomePayments进行实际扣除。 classPurchaser defcharge(购买)AwesomePayments.charge(purchase.customer.id,purchase.amount)rescue = gt,ex try_again_later(purchase.id)end,前提是上述单位代码易于理解。这可能是理想的设计。但是,为了简化测试,我们可能需要控制AwesomePayments的实例:classPurchaser definitialize(awesome_payments = AwesomePayments)@ awesome_payments = awesome_payments end definitialize(购买)definitialize(购买)。现在,您可以在测试期间通过AwesomePayments的模拟实现,以更好地控制测试。测试影响了我们的设计(尽管影响很小)。您甚至可以说此类是更好的代码。但这并非总是如此。在处理端到端测试时,我将使用相同的标准:做一些让生活更轻松的事情,但不要过分地做,请确保它是正确的。
扫描二维码关注我们
确 认