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

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

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