软件测试
- 95 次浏览
【测试与评估】测试与评估概述
视频号
微信公众号
知识星球
测试与评估(T&E)是评估各种系统、产品或技术的性能、可靠性和安全性的关键过程。它包括系统地检查和验证这些项目,以确保它们符合规定的要求并按预期运行。T&E有助于识别缺陷、弱点或需要改进的领域,使开发人员能够在最终部署之前进行必要的调整。它包括设计和执行实验、模拟和评估,以收集数据并评估物品的功能、耐用性和有效性。T&E在航空航天、军事、汽车和技术等多个行业至关重要,确保产品和系统符合质量标准并以最佳方式运行。
定义:测试与评估(T&E)是通过测试将系统或组件与需求和规范进行比较的过程。
测试与评估(T&E)的目的
测试与评估(T&E)的基本目的是提供知识,以协助风险管理,包括开发、生产、运行和维持系统和能力。T&E过程是系统工程过程(SEP)的一个组成部分,它确定性能水平并帮助开发人员纠正缺陷。
T&E向采办界提供有关系统能力和局限性的知识,以提高系统性能,优化作战中的系统使用和维持。T&E使项目经理能够了解正在开发的系统的限制(技术或操作)、关键操作问题(COI),以便在生产和部署之前解决这些问题。
主要测试与评估(T&E)参考
-
Instruction: DoD Instruction 5000.89 “Test and Evaluation”
-
Guide: DoD Test and Evaluation Management Guide – Dec 2012
-
Guide: Incorporating Test and Evaluation into DoD Acquisition Contracts
-
Guide: Cybersecurity Test and Evaluation Guidebook – 27 Oct 2015
主要测试与评估(T&E)生命周期活动
- 测试和评估策略(TES)
- 开发测试与评估(DT&E)
- 初始作战测试与评估(IOT&E)
- 作战测试与评估(OT&E)
- 后续运行测试和评估(FOT&E)
- 测试与评估总体规划(TEMP)
- 作战评估(OA)
- 实弹射击测试与评估(LFT&E)
- 资格测试和评估(QT&E)
- 软件测试与评估(ST&E)
主要测试与评估(T&E)生命周期评审
- 运行测试准备审查(OTTR)
- 测试准备审查(TRR)
测试与评估(T&E)报告
项目经理(PM)需要向OSD T&E提供测试与评估(T&E)报告。这些报告提交给作战测试与评估主任兼负责采办与维持的国防部副部长(USD(A&S))。
- 开发测试与评估(DT&E)
- 作战测试与评估(OT&E)
- 实弹射击测试与评估(LFT&E)
主要测试与评估(T&E)监督
在获取系统和提交T&E报告的整个过程中,作战测试与评估主任办公室对T&E进度进行监控。他们的监督范围延伸到主要国防采办项目(MDAP)或指定采办项目。
联合测试与评估(T&E)
联合测试与评估(JT&E)计划提供了用于分析联合军事能力的定量作战测试与评估信息,并开发了提高军事效能的潜在选项。
多服务测试与评估(T&E)
两个或多个国防部(DoD)组成部分进行多军种测试和评估。它适用于将由多个国防部组成部分获取的系统,或与另一个国防部构成部分接口的系统。所有受影响的服务机构及其各自的运营测试机构(OTA)都参与多服务测试计划的规划、实施、报告和评估。一个服务被指定为主要服务,并负责项目的管理。牵头服务部门负责编制和协调一份单一报告,反映系统的运行有效性和对每个服务部门的适用性。1.
适应性获取途径测试与评估(T&E)
通过为六种途径中的每一种提供不同的T&E方法,T&E过程已被调整为自适应获取框架的一部分。DoDI 5000.89的主要说明详细说明了对每条路径进行T&E。
T&E工作级集成产品团队(T&E WIPT)
T&E工作级综合产品团队(T&E WIPT)指导测试与评估策略(TES)的制定,并指导测试与评价(T&E)计划的执行。应在材料解决方案分析(MSA)期间尽早建立,并由项目办公室代表主持。成员应包括所有需要开发测试、运行测试或任何其他所需认证的测试数据的利益相关者组织以及用户代表。
测试与评估(T&E)资金
测试的T&E资金由国会拨款提供给管理和预算办公室(OMB),该办公室通过国防部长(SECDEF)将资金分配给各军种。PPBE程序向国会提出预算申请。PM对测试资源的请求通常在TEMP中列出。通常,系统开发由RDT&E资金提供资金,直到系统投入运营和维护。运营和维护(O&M)资金用于后续T&E(FOT&E)和系统维护。武器系统物资开发人员还负责为测试武器系统所需的新测试资源的开发提供资金。
AcquLinks和参考资料:
- Defense Acquisition Guidebook (DAG)
- DoD Instruction 5000.89 “Test and Evaluation” – 19 Nov 2020
- DoD Directive 5000.01 “Defense Acquisition System”
- DoD Instruction 5000.02 “Operation of the Defense Acquisition System”
- Army Regulation 73-1 “Test and Evaluation Policy” – 1 Aug 2006
- Template: DAG Test and Evaluation Master Plan Template
- Template: Test and Evaluation Master Plan
- Guide: DoD Test & Evaluation Management Guide – Dec 2012
- Guide: Air Force Test & Evaluation Guidebook – Dec 2004
- Guide: DAU Test and Management Guide – Jan 2005
- Guide: TEMP Review Guide – 4 April 2010
- Guide: DOT&E and TEMP Guidebook – 28 Mar 13
- Guide: Army TEMP Procedures and Guidelines – 11 Oct 1996
- Guide: Cybersecurity Test and Evaluation Guidebook – 27 Oct 2015
- Website: Title 10 USC 2366 “Survivability testing and lethality testing required before full-scale production”
- Website: 10 USC 2399 “Operational Test and Evaluation of Defense Programs”
- Website: Air Force Operational Test and Evaluation Center (AFOTEC)
- Website: Army Test and Evaluation Command
- Website: Navy Commander Operational Test and Evaluation Force
- 40 次浏览
【评估和评估】评估VS判定VS测试
视频号
微信公众号
知识星球
释义
测试: Testing
测试或测验是用来检查某人对某事的知识,以验证他或她知道或已经学到了什么。测试衡量已经达到的技能或知识水平。
评价:Evaluation
评估是根据标准和证据做出判断的方法。
看法/判定:Assessment
评估是记录知识、技能、态度和信念的方式,通常以可量化的方式。评估的目标是做出改进,而不是简单地被评判。在教育背景下,评估是描述、收集、记录、评分和解释学习信息的过程。
1.评估
评估类型
总结性
- 需求评估确定谁需要该计划,需求有多大,以及什么可以满足需求
- 可评估性评估决定了评估是否可行,以及利益相关者如何帮助塑造其有用性
- 结构化概念化有助于利益相关者定义项目或技术、目标人群和可能的结果
- 实施评估监控项目或技术交付的保真度
- 过程评估调查项目或技术的交付过程,包括可供选择的交付程序
形式性;
- 结果评估调查项目或技术是否对特定目标结果产生了明显的影响
- 影响评估是更广泛的,评估项目或技术作为一个整体的总体或净影响,无论是有意的还是无意的
- 成本效益和成本效益分析通过按美元成本和价值标准化结果来解决效率问题
- 二次分析重新检查现有数据,以解决新的问题或使用以前未使用的方法
- 荟萃分析(meta-analysis)综合了多项研究的结果估计,得出对评估问题的总体或总结判断
评估方法
- 观察检查表——收集有关程序如何运行或所产生的视觉变化的信息。
- 访谈——从个人那里获得关于他们经历的信息,或了解更多关于他们调查答案的信息
- 焦点小组——与一群人(10-12人)进行讨论,深入了解他们认为该计划的效果,或他们如何看待该计划的实施。
- 调查和问卷——从个人那里获得有关他们在烟草使用知识、态度和行为方面变化的信息。
2.判定(Assessment)
在教育中,评估一词是指教育工作者用来评估、衡量和记录学生的学业准备情况、学习进度、技能习得或教育需求的各种方法或工具。
评估类型
评估方法
检查Examinations
- 传统的总结性评估方法。
- 学生们要面对许多问题,包括短文、问题、简答题或多项选择题。
演示Presentation
向小组其他成员介绍项目或类似项目的结果。
简短回答问题Short Answer Questions
简答题的结构比选择题略差,考试中经常使用简答题
协作评估Collaborative Assessment
让学生一起工作,而不是单独工作,来制作一个项目或演示
项目Projects
“项目”有时与文章同义,但这里它指的是需要一些调查或“研究”工作以及构建论点的评估
3.测试
试验类型
- 常模参照(Norm-Referenced)
- 引用的标准(Criterion-Referenced)
- 调查(Survey)
- 诊断工具(Diagnostic Tools)
- 正式测试(Formal Tests)
- 非正式测试(Informal Tests)
- 静态(总结)测试:Static (Summative) Tests
- 动态(形成性)测试:Dynamic (Formative) Tests
测试标准
- 精确
- 稳健性
- 安全
- 可享受性
- 完整性
- 可读性
- 吸引力
- 清晰
- 无障碍(针对残疾人)
- 及时性(在需要时可用)
- 消息的通信
- 相关
- 可用性
- 12 次浏览
【软件测试】稳定性和可靠性测试在软件开发中的重要性
软件测试的某些方面经常会在那些刚接触流程的人中造成混淆——例如在稳定性和可靠性测试之间划清界限。 两者通常可以互换使用,并且有一个共同的目标,即确保系统可以在选定的时间范围内稳定运行。
在这篇文章中,我们将仔细研究什么是稳定性测试、可靠性测试的定义、它们的目标以及它们的子集。 您会发现为什么错过稳定性和可靠性测试会增加软件维护成本,以及为什么它是业务经理绝对必须的。
目录:
- 可靠性测试定义
- 可靠性测试的目的
- 可靠性测试在软件测试中的重要性
- 可靠性测试的类型
- 稳定性测试定义
- 稳定性测试的目的
- 稳定性测试在软件测试中的重要性
- 稳定性和可靠性测试解决了哪些问题?
- 结论
可靠性测试定义
可靠性测试定义是确定是否存在数据泄漏(稳定性测试)以及系统在发生故障后需要多长时间才能恢复(恢复测试)的活动。 除此之外,它还分析峰值负载下和(压力/尖峰测试)模拟组件故障(故障转移测试)期间的行为。 可靠性测试的目标是提高平均故障间隔时间 (MTBF)、平均故障时间 (MTTF) 和平均修复时间 (MTTR),并为开发团队提供一套改进指南。
软件可靠性通常以系统可用性来衡量——该值不应低于 99%。
可靠性测试的目的
可靠性测试的主要目标是验证产品在现实条件下的性能。测试还可以帮助项目团队实现其他目标,例如:
- 找出软件故障的主要驱动因素,并查明系统错误遵循的模式。可靠性测试可帮助 QA 团队检测故障原因、捕获故障时间指标并测量系统的压力水平。
- 找出在给定时间发生了多少故障,以及每个故障的平均寿命。
- 发现故障的知觉结构。根据故障分析的结果,QA 测试人员应向支持团队提供一套全面的指导方针,描述有助于降低系统故障再次发生概率的纠正措施。
- 确定关机后系统恢复的速度。为了找出软件需要重新稳定的时间,测试团队获取平均修复时间 (MTTR),将维护时间除以纠正措施的数量。
- 提高组件可靠性以确定纠正措施是否会增加组件的平均寿命,计算所需的置信水平,并制定有助于保持高系统可靠性的计划。
可靠性测试在软件测试中的重要性
软件工具用于现代社会的所有领域——包括最关键的领域,如医疗保健或安全。由于系统故障可能导致经济损失、整个行业的发展停滞并造成人员伤亡,因此 IT 专家必须有方法确定工具是否足够可靠以被大规模采用。
这就是为什么项目经理和公司所有者不能错过稳定性和可靠性测试的原因:
- 测量失效强度。熟悉最常见故障的结构、主要原因以及产品在停机之前、期间和之后的行为,可以提高风险缓解和应急计划的准确性。完成软件可靠性测试后,项目团队将能够预测故障率的增加,并提前准备一套纠正机制。
- 允许估计未来的故障。由于其广泛的范围,可靠性测试可帮助软件测试人员预测软件各个级别(单元、组件、子系统和系统)上系统故障的概率。
- 降低系统故障的风险——评估纠正措施的效率是一种可靠性测试技术。该阶段完成后,项目团队将了解所选择的对策是否是预防和消除系统故障的有效方法。
可靠性测试的类型
软件可靠性测试包括从不同角度分析系统、验证故障强度、软件恢复效率以及应用程序能够承受的压力量的几个子集。
这些是最常见的可靠性测试类型:
1.压力测试
压力测试是指使系统承受超出其原始容量的工作负载。在这种情况下,QA 工程师达到并超过系统的断点,以观察停机并计算完全恢复所需的时间。
以下是主要的压力测试活动:
- 确定系统的断点和保存使用限制;
- 确认关机后没有数据丢失或严重的功能故障;
- 确定故障模型;
- 创建断点预测的数学模型。
2.恢复测试
恢复测试意味着强制系统无法观察和分析恢复过程。恢复测试的目的是确定给定应用程序在崩溃或硬件故障后需要多长时间才能重新稳定。
在正常估计负载下的性能测试期间模拟系统故障。以下是一些属于恢复测试领域的可靠性测试示例:
- 在应用程序运行时关闭硬件,然后检查数据完整性;
- 模拟应用程序与网络进行数据交易过程时拔掉连接线,测试软件在连接中断时继续运行的能力;
- 确保系统在紧急关闭或崩溃后重新启动后可以恢复最新的更改。
3.故障转移测试
故障转移测试验证软件是否能够在服务器故障或中断期间将所有操作迁移到不同的服务器,并模拟相关系统中的故障。理想情况下,开发团队努力实现自动故障转移,这意味着尽管设备、服务器或网络停机,系统仍将保持正常运行。
4. 稳定性测试
稳定性测试是一个可靠性测试子集,指的是验证不存在资源泄漏和变量去初始化的正确性。在运行稳定性测试时,软件测试人员强调错误处理验证和可扩展性。
软件稳定性测试的主要目的是在产品公开发布之前确定应用程序的局限性。
稳定性测试定义
稳定性测试是一系列活动,旨在验证软件产品在高压力水平下是否可以在既定时间范围内或超出既定时间范围内执行而没有性能缺陷或崩溃。
由于应用程序的稳定性只能在对其进行长时间监控后才能确定,因此测试活动包括重复执行测试并将结果与初始结果进行比较。
稳定性测试的目的
稳定性测试是质量保证的重要组成部分,因为它有助于确定软件的局限性,更深入地了解项目团队在发布后必须面对的问题,并在发布之前确定应该改进的领域最终构建。
以下是完成稳定性测试协议的主要目标:
- 测试系统在接近最大负载下的稳定性,确保系统能够处理高流量和数据负载。
- 在发布之前监控被测系统的有效性并增加团队对软件无错误开发过程的信心。
- 确保系统在开发环境之外没有内存泄漏、前所未有的关闭或异常行为。
稳定性测试在软件测试中的重要性
业务经理只能通过在延长的时间范围内检查软件项目来确定其软件项目的稳定性。通过将繁重的负载放在应用程序上并测试系统响应,项目团队已经做好了处理发布后问题的准备。
除此之外,稳定性测试有助于识别只会在较长时间内显示的故障和崩溃——这是提供这种视角的唯一测试形式。
至于稳定性测试在质量保证中的作用,这就是为什么这个阶段是任何测试周期的重要组成部分:
- 提供对系统性能的信心并提高预测精度。
- 确保系统可以在并发用户或存储数据的高负载下长时间工作。
- 通过查明和消除最常见和破坏性系统故障的原因,降低系统停机的几率。
- 检测主要系统缺陷——从系统内存(会话、数据结构等)中释放不正确的对象
稳定性和可靠性测试解决了哪些问题?
除了通过快速查明功能和性能问题并确保系统在高负载下不会降级来帮助减轻系统故障和关闭的风险外,稳定性和可靠性测试还解决了广泛的软件维护问题。
- 崩溃和挂起 — 稳定性和可靠性测试验证系统的性能一直到断点,识别停机和响应问题。这些测试旨在让开发人员深入了解哪些软件组件是导致崩溃的原因,并指导团队进行软件改进,直到产品准备好发布。
- 数据丢失和文件损坏——可靠性和稳定性测试有助于确保用户数据不受关机影响。如果安全漏洞已被标记,在发布之前查明问题可以有更多时间来缓解可被利用的漏洞,并减少对开发团队施加的压力。
- 程序中的错误——测试将检查软件的每个组件是否存在在任何不同测试中都无法检测到的错误,并查明软件架构各个级别的故障。
- 缓存问题——稳定性和可靠性测试有助于确保微调缓存后系统性能仍然正常。
- 负载平衡问题(单独服务器集群节点的关闭/开启)——确定关闭/开启延迟。
结论
可靠性和稳定性测试过程可帮助测试团队以惊人的精度对软件的行为进行建模,并解决不规则的故障、重新启动和关闭问题。这些测试提高了所有系统组件的可见性,并为设计校正机制提供了深刻的见解。
项目团队将更好地了解严重系统故障可能产生的损害以及恢复系统所需的时间和资源——没有任何现实世界的场景会让您感到意外。
如果您想要一支熟练的软件测试人员团队来检查您项目的稳定性和可靠性,请联系性能实验室。我们的软件测试人员团队足够熟练,可以处理所有行业的小型和大型项目。我们将提供持续的支持和帮助,与开发团队合作,并记录每个测试,以便您的技术团队可以将数据用作参考点。
查看我们的产品组合,了解性能实验室测试人员如何处理测试设计和执行。给我们留言,讨论您项目的可靠性和稳定性测试。
本文:https://performancelabus.com/importance-of-stability-and-reliability-te…
- 335 次浏览
前端测试
- 50 次浏览
【前端测试】cypress 介绍
网络已经进化了。
最后,测试也是如此。
快速、简单、可靠地测试在浏览器中运行的任何东西。
我们不断收到关于“post-Selenium”web UI测试工具(如Cypress、TestCafe和Puppeteer)的积极反馈。运行端到端测试可能会带来一些挑战,比如运行过程的持续时间长、一些测试的脆弱以及在以headless模式运行测试时修复CI中的故障。我们的团队在Cypress方面有很好的经验,解决了一些常见的问题,比如缺乏性能,响应和资源加载的等待时间长。Cypress已经成为我们团队中端到端测试的首选工具。
完整的端到端测试体验。
安装Cypress测试运行程序并在本地编写测试。
设置测试
安装Cypress很简单。不需要依赖、额外下载或更改代码。
编写测试
轻松快速地编写测试,并在构建web应用程序时实时地观察它们的执行。
运行测试
在CI中调试测试与在本地运行测试一样简单。与内置并行和负载平衡。
记录测试
在仪表板中记录CI测试数据、屏幕截图和视频-和视图汇总的下一个级别的洞察力。
游戏改变者
时间旅行
Cypress在您的测试运行时获取快照。只需将鼠标悬停在命令日志中的命令上,就可以确切地看到每一步发生了什么。
Debuggability
不要再猜测测试失败的原因了。调试直接从熟悉的工具,如Chrome DevTools。我们的可读错误和堆栈跟踪使调试快速。
实时重新加载
每当您对测试进行更改时,Cypress都会自动重新加载。查看命令执行实时在您的应用程序。
自动等待
不要在测试中添加等待或睡眠。Cypress在继续之前会自动等待命令和断言。没有更多的异步地狱。
间谍,存根和时钟(Spies, stubs, and clocks)
验证和控制函数、服务器响应或计时器的行为。您喜欢的单元测试功能就在您的指尖。
网络流量控制
轻松地控制、存根和测试边缘用例,而不涉及服务器。您可以根据自己的喜好设置网络流量存根。
一致的结果
我们的架构不使用Selenium或WebDriver。向快速、一致和可靠的无缺陷测试问好。
截图和视频
查看在失败时自动拍摄的屏幕截图,或者在无头运行时查看整个测试套件的视频。
原文:https://www.cypress.io/features ,https://www.cypress.io/how-it-works
引文:https://www.thoughtworks.com/radar/tools/cypress
本文:
讨论:请加入知识星球【首席架构师圈】或者飞聊小组【首席架构师智库】
- 50 次浏览
安全测试
- 74 次浏览
【DevSecOps】实施DevSecOps策略以促进开发和安全团队之间的合作
DevOps和DevSecOps是应用程序开发和安全团队在过去几年中非常熟悉的术语,特别是当因特网连接用户需要不断更新和改进应用程序时。
事实上,DevOps正在被更多组织使用,最近的一项调查发现,49%的公司已经采用或计划采用DevOps策略。即使在尚未实施DevOps的人中,另有33%的人正在考虑这一点。
并且有充分的理由;有用。
同样的调查发现,几乎所有实施DevSecOps(97%)的人都看到了一些改进,包括更好的协作和生产力,减少编码错误,以及内部团队成员更好的士气。
仔细研究DevOps和DevSecOps之间的区别 - 以及DevSecOps的优势和最佳实践 - 演示了这种理念如何帮助开发和安全团队更好地协同工作,同时为应用程序开发过程提供额外的好处。
什么名字? DevOps与DevSecOps
这个名字说明了一切。 DevOps是软件应用程序设计和开发的开发方和操作方(服务器,网络,存储等的安装和配置)的组合。随着在云中构建和管理更多应用程序,这种混搭自然而然地发展,这为敏捷应用程序提供了更高的更新频率。
但是高频更新需要两件事:1)您的开发团队有一些值得更新的东西; 2)您的IT运营团队能够在不破坏应用程序的情况下实施这些更新。这只有在传统上将开发和运营团队分离的墙壁崩溃,创造一个真正的协作环境时才能实现 - 这正是DevOps所完成的。它打破了存在的传统孤岛,并将用户置于应用程序开发过程的中心。
但后来提出了一个重要问题:“安全性怎么样?”在开发结束时解决应用程序安全性的传统模型没有与DevOps的高频更新模型相匹配。安全性也需要成为流程中不可或缺的一部分,确保快速发布不会危及应用程序的安全性。
DevOps和安全性的结合导致了DevSecOps。这种理念维护着DevOps的一切,并将安全团队添加到流程中。它承认整个软件开发生命周期中安全的重要性,并注意开发过程中每个步骤的安全性。
这确实有其挑战。从历史上看,安全团队被视为反对障碍,阻碍发展并使得在确定问题并需要修复问题时更难以达到最后期限。
很多时候,开发人员试图忽视安全对手,开拓进取。开发人员有时会保持改变代码的意图,以防止可能存在的漏洞。不幸的是,安全性不容忽视,或者您的应用程序容易受到攻击者的攻击。
必须在开发和安全之间创建协作和沟通的环境,并考虑两个目标:
- 快速部署。
- 识别并纠正问题。
DevSecOps的好处
- 改进协作与合作 - DevSecOps宣言的第一行完美地总结了这一优势:“通过安全作为代码,我们已经并将了解到,像我们这样的安全从业者有更好的方式来运营并以更少的摩擦贡献价值“DevSecOps理念汇集了开发,运营和安全的目标,因此这三个领域都朝着快速安全部署的目标迈进。当安全团队从一开始就参与其中时,就不再被视为阻挠者;他们在团队中,而不是有意见的观众。
- 更好的应用程序安全性 - 通过将安全性集成到整个开发过程中,可以更快地识别问题并立即解决。应用程序不易受到攻击,增加了应用程序的成功率并提高了声誉。
- 提高了上市速度 - 这适用于初始版本和所有应用程序更新。 DevSecOps的灵活性不仅可以让您的应用程序更快地进入市场,而且还可以实现快速更新。由统一的DevSecOps团队支持的应用程序可以快速协调新功能和特性,从而延长应用程序的使用寿命。长期不断改进和扩展的应用程序有更长的有效窗口来赚取收入,因此您的应用程序更具竞争力,并保持这种状态。
- 节省成本 - 当涉及的代码较少时,在开发过程早期修复问题的成本更低。等到你的整个源代码完成是一个耗费更多的努力,耗尽资源。部署后修复错误是一个更大的麻烦,因为您还冒着失去客户和玷污您声誉的风险。
成功实施DevSecOps的最佳实践
- 在他们的环境中工作 - 安全团队应该熟悉开发人员正在使用的工具。这些工具应该用于在发现安全问题后立即进行通信。当安全团队在开发人员首选环境中工作时,问题更有可能得到解决。它使开发人员可以轻松查看需要修复的内容并跟踪修复的进度。
- 创建文化 - DevSecOps是一种文化。企业领导者需要灌输流程,程序和思维方式的转变,即安全性与开发一样重要。双方都需要了解对方的重要性,因此安全性了解保持开发的优先顺序,并且开发人员明白发布不安全的应用程序更新不是一种选择。
其目的是建立一种文化,在这种文化中,开发人员不会因安全问题而放慢速度;理想情况下,这也是安全专家采取措施加速应用程序安全测试过程并提高其效率的环境。整个公司必须理解这个概念并接受它,并使开发和运营的双方有效地协同工作。
但创造这种文化在很大程度上依赖于管理者和管理层。他们需要了解需要根据安全性和开发来管理最后期限。销售和营销还需要适当地设定客户的期望,以确定应用程序或更新何时准备就绪。
- 不断教育和培训员工 - 如果开发人员和安全团队成员对另一方正在发生的事情有充分的了解,他们将会更好地相互理解。围绕安全性的定期教育和培训可以帮助开发人员理解其重要性,甚至可以帮助减少首先要解决的错误。安全团队的一些基础发展教育(特别是开发人员用于跟踪进度的工具)有助于安全团队了解开发过程。安全性还可以使用开发人员首选的工具来记录问题。这是一个双赢的局面。
- 自动化 - 高效的DevSecOps方法可在开发,操作和安全性之间自动执行尽可能多的流程。这有助于团队更快地构建,测试和发布应用程序和更新。自动化在很大程度上依赖于DevSecOps安全工具和应用程序安全测试工具的使用,这些工具将在下面讨论。
DevSecOps安全测试和工具
DevSecOps要求在整个开发过程中持续执行应用程序安全性测试,以便立即解决问题。 DevSecOps方法还要求使用多种类型的应用程序安全性测试工具,以便您的应用程序在整个开发过程中获得全面的安全性。
使用的工具类型包括:
- 静态应用程序安全性测试(SAST)工具
- 动态应用程序安全性测试(DAST)工具
- 交互式应用程序安全性测试(IAST)工具
- 威胁建模工具
有关这些工具的详细信息,请参阅我们最近的博客文章。
以下是有关如何在DevSecOps环境中提高应用程序安全性测试效率的一些提示:
- 创建应用程序安全性测试级别 - 每个版本都可以进行更一般的测试,并在设定的时间表上进行更深入的测试。这样可以始终保持流程中的安全性,同时保持更新快速移动。
- 使用聊天工具促进沟通 - 诸如Slack之类的即时消息传递工具可以帮助开发,运营和安全团队成员在工作完成时进行通信。可以交换想法,并且通信线路始终是开放的。请务必在正式的问题跟踪工具(如Jira)中记录任何重要信息或决策。
- 使用应用程序漏洞管理器 - 这是一个管理应用程序安全测试工具结果并简化应用程序安全测试过程的工具。应用程序漏洞管理器具有以下优点:
- 重复使用多个工具的结果,大大减少了调查结果的数量,使安全团队更易于管理,以确定哪些威胁是最重要的,应首先解决。
- 可以自动检查代码是否符合规定,例如HIPAA,DISA-STIG和PCI DSS。标记违反的代码行,使修复更容易。
- 报告选项可以轻松地对结果进行排序和组织。报告还可用于跟踪补救进度,因此您可以确保您的开发团队始终处于安全问题之上。
- 标记包含错误的代码行,可以从一个中央控制台轻松分配和跟踪问题。
- 与开发工作流程集成允许您的安全团队在开发人员习惯的环境中工作。例如,一个好的工具将与Eclipse和Jira集成,因此开发人员可以轻松跟踪问题,而无需离开他们喜欢的开发环境。
- 有些工具提供混合分析,它可以比较SAST工具和DAST工具的结果,以快速确定哪些漏洞实际可利用。这样可以自动完成冗长且昂贵的确认过程,并提供一系列高优先级漏洞。
DevSecOps是创建有竞争力的创收应用程序的理想方法。在DevSecOps文化中,所有方面都有效地协同工作,因此应用程序和未来的更新是安全的并且可以快速发布。创建一个有效的DevSecOps文化确实需要一些工作,但是如果有正确的态度和正确的工具,它就可以实现。
原文:https://codedx.com/how-devsecops-boosts-cooperation-on-your-team/
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 29 次浏览
【安全测试】 6 DevSecOps最佳实践:尽早并经常自动化
希望将安全性集成到其DevOps管道中的组织应采用将应用程序开发,IT操作和安全团队统一在一个共同的DevSecOps规则下的工具和实践。
目标是使安全性成为软件开发工作流程的一部分,而不是像在瀑布式开发模型中那样在循环的后期使用它。
这种转变正在颠覆传统观念,即安全控制应该如何,何时以及在何处集成到软件中,并且正在挑战曾经孤立的群体,以寻找合作的方式来提供快速但安全的代码发布。
“DevSecOps的受欢迎程度稳步上升,”WhiteHat Security首席安全研究官Ryan O'Leary表示。近年来在DevOps模型下结合开发和运营团队的公司通常以更快的速度成功发布代码。
但是,这种趋势加剧了将安全性集成到流程中的需求,因为您发布代码的速度越快,也可以释放更快的漏洞,他说。
以下是寻求实施DevSecOps的组织的关键最佳实践。
1.让自动化成为你的朋友
速度是DevOps的主要原则之一。在持续集成和持续部署(CI / CD)环境中,您可以多快地将代码输出门并进入生产阶段,几乎可以胜过其他任何事情。安全旅程的首席执行官,首席顾问兼联合创始人克里斯罗密欧说,为了使安全性成为这个工作流程的一部分,它需要实现自动化。
安全控制和测试需要在开发生命周期的早期和任何地方进行嵌入,并且需要以自动化方式进行,因为组织正在为单个应用程序每天将新版本的代码推向生产50次,他说。
“使用DevOps,你必须超级快速地移动。在这个过程中没有'手动'。如果你没有自动化,你将永远不会成功。”
-Chris Romeo
在具有高度成熟的DevOps实践的组织中,自动化已成为DevSecOps的关键特征。在今年早些时候对近2,300名IT专业人员进行的Sonatype调查中,大约40%的受访者在整个开发生命周期中都进行了自动安全测试。当自动安全测试在生产之前运行时,这不是瀑布式开发模型所发生的情况。
从源代码分析到集成和部署后监控,越来越多的具有一系列功能的工具可用于在整个软件开发生命周期中进行安全性分析和测试。这些包括Checkmarx,Splunk,Contrast Security,Sonatype,Tanium,InSpec,FireEye和Metasploit。
思想自动化
罗密欧表示,在进行安全测试自动化时,请谨慎行事。例如,如果您对夜间构建执行静态应用程序安全性测试(SAST),请确保仅扫描当天为代码所做的更改中感兴趣的内容。
尝试每天对整个应用程序源代码运行自动扫描可能会耗费大量时间并且会破坏您跟上日常更改的能力。
还要考虑将自动化动态应用程序安全性测试(DAST)嵌入到软件开发生命周期中。与静态分析(侧重于在代码本身中发现潜在的安全性问题)不同,DAST在应用程序运行时实时查找漏洞。
自动执行DAST扫描并针对最近或新的代码更改运行这些扫描,以捕获Open Web Application Security Project(OWASP)列表中列出的最常见缺陷(例如SQL注入错误)中列出的安全漏洞,您可能在静态分析期间错过了这些漏洞罗密欧说,你的应用程序代码。您需要以自动化方式,因为您只需要通过一组测试就不会知道您可能会错过什么。
ShiftLeft的联合创始人兼首席执行官Manish Gupta表示,在CI平台中添加自动安全分析可以限制软件开发生命周期早期的易受攻击代码的引入。
自动化可与轻量级嵌入式代理结合使用,以提供有关从自动安全分析中检测到的问题的相关运行时分析。 Gupta表示,采用这些方法可以使开发人员更容易确定需要修复的代码问题的优先级。
2.检查代码依赖性
尽管人们越来越担心使用第三方软件组件的风险,但企业在应用程序中使用的开源软件更多,而不是更少,根据Black Duck Software在2017年初进行的一项调查。
该公司对1,000多个商业应用程序进行的单独审计显示,其中96%包括开源组件。超过六分之一的应用程序包含这些组件中已知的安全漏洞,有些已经存在长达四年。尽管如此,只有27%的受访者表示他们拥有自动识别和补救跟踪功能,可以解决开源软件中的已知缺陷。
Gupta说,了解开源使用是更广泛采用DevSecOps实践的关键。 “云以前所未有的方式推动了创新,使公司能够更快地满足客户需求。这种创新步伐也促使开源软件越来越多地用于组装应用程序,而不是从头开始开发。”
Gupta说,开发人员通常没有时间审查其开源库中的代码或阅读文档,因此管理开源和第三方组件的自动化流程是DevSecOps的基本要求。您需要知道您的开源使用是否导致代码中的上下文和其他漏洞,以及这些漏洞可能对依赖代码产生的影响。
代码相关性检查是DevSecOps的基础,而诸如OWASP Dependency-Check之类的实用程序可以帮助确保您不使用软件中已知漏洞的代码,Security Journey的Romeo说。
OWASP实用程序通过扫描您的代码和相关的开源组件库来工作,以查看它们是否包含任何关键的OWASP缺陷。它适用于开源软件中所有已知漏洞的不断更新的数据库。
3.不要咬人比别人咬的更多
SAST工具允许开发人员在编写代码时扫描代码,以便他们可以收到有关可能导致安全问题的问题的即时反馈。这些工具可帮助开发人员识别和修复潜在的安全漏洞,这是正常工作流程的一部分,因此应该是DevSecOps实践的重要组成部分。
然而,引入这些工具时的关键是要小心思考。罗密欧说,通常情况下,当安全团队在CI / CD链中实施静态测试工具时,团队倾向于检查一大堆安全问题,最终只会给开发人员带来问题。
相反,最好一次打开一个或两个安全检查,让开发人员习惯于将安全规则合并到他们的工作流程中。
例如,在开发中引入SAST工具时,您可以首先启用捕获SQL注入错误的规则。一旦您的开发人员看到该工具如何帮助他们在编码期间捕获错误,他们就更有可能想要使用它。 “在开启越来越多的规则之前,你需要建立对工具的信任。”
构建DevSecOps功能时,将其分解为可管理的块。 “解决这个问题的最佳方法是查看DevSecOps版本中所有不同活动的整体集合,”罗密欧说。选择一个开始并证明它有效,然后再转向下一个。
他说,进入和破坏事物的安全专业人员只会放慢速度并与开发人员发生冲突。在开始时要小心思考,并在采取下一步措施之前取得一些成功。
“你在这里处理的是一种不同的文化。”
-Romeo
4.有些工具比其他工具更有用
将安全性插入敏捷DevOps所需的许多工具仍在出现,因此在购买时要记住一些关键注意事项。
例如,整合是至关重要的,WhiteHat Security的O'Leary说。 “安全产品需要能够集成到开发流程中,并使开发和安全团队能够一起工作,而不是仅仅把东西扔到篱笆上,”他说。
如果开发人员必须不遗余力地开始扫描,他们很可能会放弃扫描工具。 “安全产品需要让开发人员能够轻松快速启动扫描并获得结果,而无需离开现有工具集,”O'Leary说。
其他关键要求是速度和准确性。安全工具应该快速工作。但O'Leary告诫说,误报可能是DevOps环境中的绝对杀手。
需要开发人员或安全工程师抽出时间来验证扫描结果的工具几乎没有帮助。您的工具生成的结果需要快速,准确且立即可操作。
“误报是快速发展的死亡。”
-Ryan O'Leary
为瀑布开发模型设计的安全工具在DevSecOps世界中几乎没有用处。 ShiftLeft的Gupta表示,您需要的工具可以帮助您的开发人员在编写软件时识别漏洞并确定其优先级。代码漏洞的识别需要基于对软件本身的理解,而不是将其与签名进行匹配。
Gupta对于购买此类工具时组织需要考虑的内容提出了一些建议。您选择的任何工具都应该可以保护您免受已知漏洞的影响,但不会受到未知威胁和关键OWASP十大风险的影响。
这些工具还可以帮助您识别和解决您使用的开源软件组件中的风险,并以帮助您缩短平均解决时间的方式识别问题。
“广泛采用DevSecOps的挑战是提出不会对发布和部署周期造成拖累的工具和流程。”
-Manish Gupta
5.威胁建模很难,但无论如何都要做
SANS Institute建议您在转移到DevSecOps之前进行威胁建模和风险评估。威胁建模练习可以帮助您的安全组织更好地了解您的资产受到的威胁,资产的类型和敏感性,现有的保护这些资产的控制措施以及需要解决的控制措施中的任何差距。
此类评估有助于识别其他安全方法可能遗漏的应用程序架构和设计中的缺陷。
罗密欧说,在DevOps环境中进行威胁建模可能具有挑战性,因为它可以减缓CI / CD环境的速度。
“DevOps更多的是关于动态设计。实际上,有些DevOps人员根本不做任何设计并说代码就是他们的设计。这很危险。”
-Romeo
您无法以与DevOps几乎所有其他方面相同的方式自动化威胁建模过程。但罗密欧表示,威胁建模对于DevOps工作的整体成功仍然至关重要,因为它可以让您的开发人员从攻击者的角度考虑他们的软件。
6.培训开发人员进行安全编码
采用DevSecOps时,您将面临多重挑战。其中最大的问题就是从利益相关者那里获得支持。 O'Leary说,开发,安全和运营团队经常在自己的孤岛中运营,并有自己的议程和任务。 “向公司提出这些组织可以合并的案例有时候会有点困难。”
获得培训开发团队进行安全编码所需的投资和时间是另一项重大挑战。 “开发人员通常不知道他们是以不安全的方式编码。它仍然没有经常教授,并且不是开发团队的优先考虑,”O'Leary说。他说,必须在培训开发人员的安全方面进行投资。
“防止漏洞的最佳方法是永远不要编写代码。”
-O'Leary
许多DevSecOps实践和工具仍在不断涌现,目前对DevSecOps的定义仍未达成共识。但很明显,在持续集成和快速发布周期的世界中,您不能再忽视应用程序安全性。 Gupta说,安全是另一个共同的主题。
“它越来越成为一种共同的责任,建立在软件开发生命周期中的每个人都对其负责的理念之上。”
原文:https://techbeacon.com/security/6-devsecops-best-practices-automate-early-often
本文:
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 107 次浏览
【安全测试】Web应用程序的渗透测试和漏洞评估的重要性
Trustwave的2018年全球安全报告发现,所有Web应用程序都容易受到攻击。是的,你没有看错。所有应用程序至少有一个漏洞,每个应用程序发现的平均漏洞数量为11个。
该报告还发现2017年报告的漏洞数量急剧增加。这主要是由于使用Web应用程序的人数和市场上的Web应用程序数量急剧增加。
为了保护您的Web应用程序免受攻击者的侵害,您的Web应用程序测试必须全面,从多个角度分析您的应用程序。一个“完成”的方法是不够的。适当的方法包括渗透测试,漏洞评估和应用程序漏洞相关性。
Web应用程序渗透测试:它确实非常重要
渗透测试或笔测试是针对您的Web应用程序的模拟攻击。以前,渗透测试主要在网络上执行,而不是在这些网络上运行的应用程序。
笔测试的目的是识别可从外部攻击者利用的应用程序中的漏洞。可以针对应用程序中使用的各种类型的代码和系统(如API和服务器)执行渗透测试。
由于引入了安全软件开发生命周期(SSDL),在应用程序级别的渗透测试变得更加普遍。 SSDL在应用程序开发和维护的所有阶段都赋予安全性更大的重要性。
最佳实践要求Web应用程序应每季度进行一次渗透测试。但现实却截然不同。最近的一项研究发现,大多数组织都没有遵循这一建议,其中约三分之一的受访者每年仅对其应用程序进行一次笔试。
笔测试通常涉及五个阶段:
- 规划和数据收集 - 定义渗透测试的目标。将包括哪些系统?将使用哪些测试方法?例如,收集攻击目标上的数据,可能包括网络或域名。
- 扫描工具用于收集目标上的更多数据和信息。示例包括漏洞扫描程序和DAST工具,将在下一节中详细讨论。
- 获取访问权限 - Web应用程序攻击(如跨站点脚本或SQL注入)将启动以暴露漏洞。笔测试者试图通过窃取数据或增加权限来暴露这些漏洞。目标是了解可以造成多大的伤害。
- 维护访问权限 - 确定是否可以使用公开的漏洞在应用程序中实现持久存在。换句话说,攻击者可以深入了解Web应用程序,访问敏感数据并造成更多伤害吗?
- 覆盖追踪 - 攻击者注意保持未被发现。必须将对系统所做的更改返回到不会引发红旗的状态。
渗透测试会生成一份正式报告,详细说明被利用的漏洞,测试人员能够保持多久未被发现以及暴露的敏感数据。此信息用于修复漏洞并提高Web应用程序的安全性,以帮助防止将来发生真正的攻击。
渗透测试方法包括:
- 外部测试 - 仅针对互联网上可见的系统和资产(例如Web应用程序本身)。测试的目标是获得对应用程序及其数据的访问权限。
- 内部测试 - 笔式测试仪可以访问防火墙后面的应用程序。潜在的情况可能是流氓员工或员工的失窃凭证。
- 盲测 - 笔测试器给出了公司的名称,但没有别的。这可以实时模拟实际的应用程序攻击。
- 双盲测试 - 这类似于盲测,但安全团队并未了解模拟。他们没有时间为袭击做准备。
- 有针对性的测试 - 渗透测试人员和安全团队协同工作,相互通知攻击应用程序和防御攻击所采取的步骤。这可以作为一种训练练习,在攻击期间提供实时反馈。
渗透测试在很大程度上是一个手动过程。人类测试人员需要应用更高级别的技能来正确识别Web应用程序中的所有可利用漏洞。但是有一些工具可以帮助进行渗透测试:
- OWASP ZAP-OWASP Zed攻击代理(ZAP)是一种免费的安全工具,由全球数百名志愿者维护。它是笔测试人员帮助识别Web应用程序中的安全漏洞的绝佳资源。
- Burp Suite-Burp Suite是一个用于Web应用程序安全测试的图形工具。您可以购买免费版和升级版。免费版本非常有限,但高级版本可以对Web应用程序执行自动攻击。该工具可以检测SQL注入,跨站点脚本和其他漏洞。反馈驱动的扫描逻辑模仿人类测试人员。
- Code Pulse-Code Pulse是一种开源工具,可在笔测试期间自动检测覆盖信息。在执行代码时,应用程序攻击面的可视化表示会实时更新,通知笔测试人员应用程序的哪些部分已经过测试。
漏洞测试:您真的需要做多少?
漏洞评估可识别Web应用程序中的安全漏洞。这是通过应用程序漏洞测试完成的。
市场上有许多工具可以帮助进行威胁和漏洞评估。确保您的应用程序不会让您的用户(和您的公司)向攻击者开放的唯一方法是使用工具组合。
为什么?因为不同的工具识别不同的问题工具组合提供全面的Web应用程序安全性。应该使用的工具包括:
- 静态应用程序安全性测试(SAST)工具 - 这些工具检查安全漏洞的源代码,字节代码或应用程序二进制文件。示例包括Fortify SCA,CodeSonar和Veracode。他们寻找开发人员可能不知道的已知漏洞模式。它们具有可扩展性,可通过扫描代码而无需手动操作来自动执行部分测试过程。但是,SAST工具往往会识别大量的误报,需要对结果进行分析和优先排序,这需要时间和资源。
- 动态应用程序安全性测试(DAST)工具-DAST工具在运行时从外部接近应用程序,模拟真正的攻击者。示例包括Burp Suite,HP WebInspect和Appscan。由于DAST工具需要正在运行的应用程序,因此在开发达到某个阶段之前无法使用它们,并且它们无法在早期发现问题。
- 交互式应用程序安全性测试(IAST)工具 - 这些工具结合了SAST和DAST工具,使用检测技术在应用程序运行时使用信息来查找漏洞。一些为IAST测试提供集成解决方案的公司是Acunetix,HPE和IBM。 IAST工具识别较少的误报并提供更全面的代码覆盖。但这些工具背后的技术可能会对应用程序性能产生负面影响。由于这些性能问题,测试体验可能与实际用户体验不同。
- 软件组合分析(SCA)工具 - 第三方组件(如开源库和框架)通常用于Web应用程序开发,以加快开发过程。这是一种很好的方法,但是这些第三方组件需要保持最新并扫描漏洞。假设其他人已采取必要措施确保给定的库或框架是安全的,则会使您的应用程序面临安全风险。这相当于邀请陌生人进入你的家。 SCA工具分析应用程序中使用的源代码,库和框架,以在部署应用程序之前识别安全漏洞或许可问题。这里唯一需要注意的是,您需要准确的第三方组件库存,以确保检查所有外部部件。例子包括Black Duck和Sonatype。
这些类型的工具中的每一种都有优点和缺点,使混合方法最佳。这为您的应用程序提供了理想的覆盖范围,并降低了面临威胁和漏洞的风险。有关这些工具的更多详细信息,请访问我们的博客
应用程序漏洞关联:它是什么以及它如何帮助您?
所有这些工具和测试对于开发安全应用程序都很重要。但是,这些工具的管理和它们产生的报告量(以及每个报告中的调查结果量)可能是一个挑战。
应用程序漏洞关联(AVC)工具是Gartner确定的新策略,用于优先处理代码中的缺陷并简化应用程序安全性和漏洞管理流程。基本上,AVC工具解决了管理多个工具及其报告的难题。
好处包括:
- 重复数据删除 - 自动删除大量报告的重复结果。您将收到一份包含一组结果的报告。该工具适用于多种测试技术,包括SAST,DAST,IAST,SCA,威胁建模和人工审核。也可以手动输入渗透测试结果,或者可以通过插件自动输入笔测试工具的结果。
- SAST和DAST结果的相关性 - SAST工具可识别潜在的漏洞,而DAST工具可识别哪些漏洞实际可利用。通过称为“混合分析”的过程将所有这些结果组合在一起,可以让您了解哪些威胁是真实的并且具有最高优先级。
- 补救管理-AVC工具可识别存在漏洞的特定代码行以及相邻的漏洞和漏洞。通过集中控制台,您可以分配,跟踪和监控修复进度。
- 工作流集成 - 与Eclipse等流行环境集成,使开发人员可以轻松解决问题。嵌入持续集成环境的工具和Jira问题跟踪工具提供了额外的简化。与Jenkins构建服务器集成允许您在Jenkins中启动分析。
- 报告 - 各种报告可以轻松地对测试结果进行排序并有效跟踪补救措施。例如,报告修复问题所需的时间可帮助您确保快速进行补救。
- 合规性检查 - 根据HIPAA,DISA-STIG和PCI-DSS等法规自动检查您的代码库。标记违规行代码,并识别特定违规行为。建议遵守法规。
显然,您希望使用提供强大功能和可靠技术的工具。 Gartner将Code Dx确定为AVC类别的领导者,同时也是Application Security Testing Orchestration类别的领导者。
处理渗透测试和漏洞测试结果的想法可以使您的开发和安全团队在山上奔跑。但是,如果您想要创建一个不会让您的用户和您的声誉暴露的安全应用程序,则必须进行全面测试。应用程序漏洞关联工具简化了笔和漏洞测试的管理,使您的团队无法隐藏。全面和高效与AVC齐头并进。
本文:
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 142 次浏览
【安全测试】如何以正确的方式测试加密的应用程序
你如何测试数亿行代码或数百亿个晶体管?这很难。但是当你实施加密时,它会更难。
今天的加密技术并不容易理解。它经常对数千位值进行复杂的计算。并且它经常使用随机数进行某些计算。
例如,当您生成加密密钥时,您需要生成大量随机(实际上是伪随机)位。如果某个键看起来不像随机位,则攻击者可能更容易猜测它。这意味着您的加密技术不能提供尽可能多的安全性,这很糟糕。
这就是为什么它如此复杂,以及一些简化测试加密软件测试的技巧。
已知与随机值
如果您正在测试实现加密的硬件,则使用随机值会使测试更加困难。测试复杂的东西很难,如果你不能用很多已知的输入输出对进行测试,那就更难了。如果您的输入在每次进行测试时都会发生变化,就像您使用随机数一样,测试可能几乎是不可能的。
要解决此问题,大多数(可能是所有)实现加密的硬件都有办法绕过其随机数生成器的输出并在测试中使用已知值。
这种未记录的特征在硬件中令人惊讶地普遍。从1996年5月到1998年8月,Dobb博士的杂志甚至还有“未记载的角落”,这是一个描述其中一些内容的专栏。
最近的例子包括rosenbridge后门,其中微处理器的未记录功能可以让任何应用程序获得操作系统的root访问权限。另一个备受瞩目的问题是使用英特尔的内部信号架构可视化(VISA)来监控其他芯片正在做什么,实质上是为黑客提供了一个逻辑分析仪,可用于探测其他芯片的运行。
这些未记录的功能(可称为“后门”)可能存在于实现使用随机数的加密技术的所有硬件中。这基本上就是全部。
可以使硬件在其中断开或禁用绕过随机数使用的方式,但聪明的黑客可能能够找到重新启用后门的方法。或者在发货之前它可能不会被禁用。
这是一个可能无法避免的权衡:如果你想测试你的硬件,你可能还需要在其中引入一个后门,这意味着它可能不像你想要的那样安全。 。
情况正在恶化
假设你可以穿越时间,也许正如H.G. Wells在The Time Machine中描述的那样。如果我们可以跳到22世纪并与那些使用当时流行的技术的工程师交谈,那么他们很可能会熟悉我们今天如何测试硬件和软件。
不幸的是,这可能是因为我们测试技术的能力跟不上我们构建技术的能力,我们的许多失败可能最终会成为22世纪教科书中的案例研究。
回到网络时代,我工作的公司每三个开发工程师就有一个测试工程师。今天,这个比例更像是每个开发工程师的一名测试工程师。在过去的20年里,测试肯定变得更加困难和昂贵,并且它看起来不会很快变得容易。
在过去的几十年中,软件中使用的代码行数急剧增加。当我离开研究生院并获得我在科技行业的第一份工作时,有传说中的应用程序的故事使用了100万行代码。
这些可能是杜撰的。我从来没有见过任何与这些怪物一起工作过的人。可能情况是,100万行代码与标记为“rex quondam rexque futurus”(“曾经和未来的国王”)的墓碑一样神秘,并且只是为了吓唬新工程师。
百万俱乐部
今天,拥有一百万行代码的应用程序真的不那么令人兴奋。大约12年前,当我们在我曾经工作过的初创公司进行第一次安全源代码审查时,我有点惊讶地发现我们用来解析XML的第三方库之一的源代码包含超过100万行。
很容易找到目前使用数亿行代码的情况。在2016年国际消费电子展上,福特汽车公司指出,目前已有超过1.5亿行代码进入其F-150皮卡。高端汽车可能拥有更多,几乎肯定超过2亿线。如今拥有数百万行代码并不是什么大不了的事。
硬件变得越来越复杂。在互联网泡沫破灭之前,我记得英特尔如何能够制造包含310万个晶体管的奔腾处理器。
今天,制造了包括数百亿个晶体管的集成电路。如果你想到这一点,那就太惊人了:数十亿的组件,所有这些组件的工作方式大致与他们应该的一样。这是科幻小说作家亚瑟·C·克拉克告诉我们的那种足够先进的技术,与魔术无法区分。
为什么测试软件更容易
在某些方面,软件比硬件更容易测试。在调试模式下编译代码使测试更容易,一旦完成调试,在发布模式下编译相对容易。
但要确保正确实施加密仍然非常困难。加密算法的中间结果和输出通常看起来像数百甚至数千个随机位,这使得调试实现它们的代码变得棘手。
你永远不会得到像“This String”这样的东西作为加密算法的中间结果。相反,你会得到更像:
"0x7649abac8119b246cee98e9b12e9197d8964e0b149c10b7b682e6e39aaeb731c."
啊。
简化测试的方法
幸运的是,这个问题有一个简单的解决方案:不要编写自己的加密软件!如果你现在参加大学课程大致是Crypto 101,你将学习加密算法如何工作以及为什么它们是安全的。然后你会被告知永远不要自己尝试这个,因为做错事的可能性太大了。
相反,请使用已经验证过标准的现有加密库,例如美国政府的 FIPS 140-2, "Security Requirements for Cryptographic Modules."。这不一定很难或很昂贵。例如,OpenSSL的一个版本已经获得了FIPS 140-2验证。
不幸的是,很多人没有使用Crypto 101类,最终试图实现他们自己的加密算法版本。这很难做对。尝试这样做真的不是一个好主意。
因此,要注意实现加密的硬件,因为可测试性可能会在其中加入后门。从来没有,永远不会实现加密,因为有一个可以使用的已知良好的解决方案。
原文:https://techbeacon.com/security/how-test-encrypted-apps-right-way
本文:
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 32 次浏览
【安全测试】应用程序漏洞测试软件 - 帮助保护软件安全的工具
您已经接受了应用程序漏洞测试的重要性,以确保软件的安全性。非常好。在应用程序漏洞测试软件方面有很多选择,因此知道哪些工具是正确的工具可能会让人感到困惑。在应用程序漏洞测试方面,不同的工具可以识别不同的问题,因此您需要考虑使用多个问题。这使得对不同类型的工具及其重要性的一般理解非常重要。
您可以使用许多工具,包括开源和商业产品。开源工具是免费的,任何人都可以下载。这使它们成为一种方便且低成本的测试方法 - 并且是一种开始使用的好方法。另一方面,商业工具是许可的,使用受到限制,当然,它们必须付费。但是,使用商业工具获得的部分功能是技术支持和更高的安全性。商业工具通常也更先进,具有更多功能。开源和商业应用程序漏洞测试工具都有其价值和地位,但统计数据表明,许多组织没有充分利用这些工具。
SANS最近的一项调查发现,10%的企业根本没有测试他们的安全应用程序,另外24%的企业每年测试一次或更少。此外,只有12%的人会定期进行测试。
应用程序漏洞测试中的这些漏洞使组织容易受到可轻松避免的安全威胁。企业需要在应用程序漏洞测试中更加全面。虽然开源和商业测试工具都可以提供帮助,但工具可以进一步细分为特定类型,帮助组织了解每种工具带来的内容。然后可以制定和部署适当的应用程序漏洞测试策略。
静态应用程序安全性测试(SAST)工具
我们将讨论的第一类应用程序漏洞测试工具是静态应用程序安全测试(SAST)工具。 SAST工具也称为源代码分析工具或白盒测试。这些工具检查安全漏洞的源代码,字节代码或应用程序二进制文件。
由于多种原因,SAST工具对于应用程序漏洞测试很有价值。具体而言,它们具有以下优点:
- 他们发现理论问题,寻找开发人员可能不知道的已知漏洞模式
- 您可以自动执行测试过程,因为您无需人工干预即可扫描代码
- 它们是可扩展的
- 它们非常适合可以自信地自动发现的问题,例如SQL注入缺陷。这里需要注意的是,虽然有一些工具和技术可以帮助防止SQL注入攻击,但它们并不总是正确实现,如果有的话,这使得它成为数据库驱动应用程序的主要攻击媒介之一。
- 开发人员很容易消化输出,因为这些工具可以识别存在问题的代码中的确切位置
但是,要记住SAST工具存在一些缺点。要注意的主要问题是:
- SAST倾向于识别大量的误报
- 结果需要进行分类,需要时间来分析并优先考虑结果
- 许多漏洞(例如身份验证问题)都不容易自动发现。很难证明发现的“问题”是否是可验证的安全威胁
- 许多SAST工具在分析无法编译的代码方面做得很差,因此您需要完整且可构建的源代码包
- SAST可能非常耗时,并且可能对敏捷开发及其相关的快速开发周期产生负面影响
当您探索SAST工具的市场时,您将遇到的一些大牌是Fortify SCA(静态代码分析器),CodeSonar,Veracode和Checkmarx。这些都是市场上声誉良好的名称,在您根据测试需求评估这些工具时,应考虑上面讨论的利弊。
动态应用程序安全性测试(DAST)工具
下一个主要类型的应用程序漏洞测试工具是动态应用程序安全测试(DAST)工具。 DAST工具也称为漏洞扫描工具或黑盒测试,从外部接近应用程序,如“机器人黑客”,搜索漏洞。 DAST工具对于应用程序漏洞测试很重要,因为它们:
- 在应用程序运行时检查它,尝试以意想不到的方式对其进行操作以暴露潜在的漏洞
- 模仿攻击者对应用程序知之甚少,模拟外部黑客
- 提供自动化测试流程,因为它们独立于人工协助运行
- 提供可扩展性
DAST工具的缺点包括:
- 它们需要运行的应用程序,因此在应用程序达到完成级别之前,您无法使用它们
- 在开发周期的后期使用它们使得它们不太适合在开发过程早期识别和纠正问题
- 识别威胁可能需要更长时间,因为您可能需要操纵工具以使其尽可能多地覆盖应用程序的代码
- 它们可能无法充分模仿具有应用程序内部知识的人员的攻击,而高级黑客可能能够实现
DAST领域的大牌包括商业和开源工具,如BurpSuite,HP WebInspect,OWASP ZAP和Appscan。与SAST工具一样,在选择哪种DAST工具最适合您的应用时,必须考虑优缺点。
交互式应用程序安全性测试(IAST)工具
随着我们在复杂性方面的提升,我们开始使用交互式应用程序安全测试(IAST)工具,它结合了SAST和DAST。 IAST工具 - 也称为Glass Box测试 - 使用工具技术在应用程序运行时利用其中的信息来查找漏洞。
IAST工具为应用程序漏洞测试带来了诸多好处,使测试人员能够:
- 更准确地查找漏洞,从而减少误报
- 提供更全面的应用程序代码覆盖
- 根据需要进行规模测试
- 为开发人员提供即时反馈,以便及时解决问题
- 将测试轻松纳入开发过程
IAST工具的缺点是:
- 仪器可能会对应用程序性能产生负面影响,因此您的测试体验可能与实际用户体验不同
- 它们代表了相对较新的技术,因此可能出现其他潜在的问题或缺点
一些供应商为这两种方法提供了工具,但它们通常作为两个单独的工具提供。现在有一些提供集成解决方案的厂商,如Acunetix,HPE和IBM,使它们成为应用安全测试的优秀工具。
威胁建模工具
威胁建模工具是应用程序漏洞测试的另一种资源。威胁建模是识别,评估和确定优先级的潜在漏洞的过程。可以采用许多方法,这些方法将在下面详述,并且从潜在攻击者的角度进行测试。威胁建模通过识别应该受到最多关注的威胁和漏洞,并找到最容易受到攻击的区域来节省时间和资源。
一些最常见的威胁建模工具包括:
- STRIDE - 根据攻击者可能具有的各种动机对已知威胁进行分类,例如篡改数据或身份欺骗。
- DREAD - 比较与每个已知威胁相关的风险等级并确定其优先级。
- Trike - 使用基于风险的方法的框架。
- AS / NZS 4360 - 澳大利亚/新西兰标准,是第一个(也是唯一一个)风险记录和管理标准。
- 常见漏洞评分系统(CVSS) - 评估威胁和漏洞严重程度的行业标准。
- OCTAVE - 一种专注于组织风险而非技术风险的模型。
- ThreatModel SDK - 一个Java库,使供应商能够分析来自最常见的威胁建模工具的报告。
所采用的特定威胁建模方法并不像确保在测试过程中选择和仔细执行至少一种方法那样重要。
手动测试
如果不提及手动测试,就不会讨论应用程序漏洞测试:良好的,老式的代码审查。优秀的开发团队应该将代码审查作为标准开发流程来确保质量代码,但应该将安全思维纳入其中。在您的代码流程中添加安全检查(可能涉及对问题有特定了解的其他人员)可能会使您的敏捷开发工作流程保持运转,同时仍在寻找安全威胁和潜在漏洞。
手动代码审查通常从安全测试人员开始接收开发人员对应用程序的简报开始。然后根据时间,资源和预算制定计划。目标应该是根据他们的专业领域使用测试人员,让他们测试他们最了解的领域。必须审查所有发现的误报,并与开发团队分享真实的积极因素。
手动测试可以减少误报,并可以识别自动化工具遗漏的问题。然而,考虑到所需的(人类)资源,这种测试也难以扩展。
混合方法是最好的
不同应用程序漏洞测试工具的概述可以快速演示每种类型的工具都有优点和缺点。这就是为什么只使用一种工具或一种工具进行测试会使您的应用程序面临更大的风险。利用来自多个类别的工具的混合方法可提供最佳覆盖率并降低应用程序的风险。随着您的前进并为应用程序安全性测试创建正式的策略,OWASP Benchmark是评估各种类型的测试工具的宝贵资源。这将帮助您为您的应用和业务选择最好的。
原文:https://codedx.com/application-vulnerability-testing-software-tools-help-secure-software-2/
本文:http://pub.intelligentx.net/node/479
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 47 次浏览
【安全测试】数据,数据随处可见:如何有效管理SAST和DAST结果的泛滥
应用程序安全性测试是开发过程中不可或缺的一部分。适当的测试方法使用多种工具(和工具类型),并将应用程序安全性测试结合到应用程序开发生命周期的设计,开发和生产阶段。但是你可能会发现自己被所有这些测试工具的结果所淹没所淹没。
您如何对各种来源的结果和报告进行排序?哪些应用程序漏洞是合法且可利用的?哪些需要您立即关注?而且 - 最重要的问题之一 - 在进入下一个开发阶段之前,如何让开发人员关注这些威胁并修复它们?
在这篇文章中,我们简要介绍了应用程序安全性对敏捷软件开发的重要性以及为什么需要使用多个测试工具。我们还承认使用多种工具带来的挑战,并向您展示如何克服这些问题以快速有效地修复代码。
DevOps与DevSecOps
大多数应用程序开发人员都熟悉敏捷过程。重点是创建一个协作的工作环境,逐步完成工作。
这通常通过集成开发环境(IDE)完成,该环境可能包含源代码编辑器,编译器和解释器,以及调试器和构建自动化工具。
敏捷开发依赖于持续集成(CI)和持续开发(CD) - 这些方法要求开发人员经常将代码检入共享存储库。每次签入都由自动构建验证,可以及早发现错误并立即修复。
DevOps和DevSecOps已经成为两种密切相关的方式来遵循敏捷流程。 DevOps打破了开发和IT运营团队之间存在的传统孤岛。重点是用户体验。创建协作和沟通的环境有两个目标:
- 快速部署。
- 识别并纠正问题。
DevSecOps通过在整个软件开发生命周期中确认安全性的重要性,更进一步。从DevOps工作流程的最初阶段开始,注意开发过程的每个步骤的安全性。
应用程序安全性测试在整个开发过程中持续执行,并且问题在找到时得到修复。 DevSecOps方法与Agile软件开发一致,并提供以下几个好处:
- 一旦找到问题就更容易解决问题,而且花费更少。
- 每次迭代都为商业部署做好了准备。
- 软件可以更快地更新和部署,使您能够比竞争对手更快地满足客户和市场需求 - 使用安全的产品。
组织能够更好地满足用户需求,并以更及时有效的方式交付高价值产品。联邦机构是拥有这种方法的领先组织之一。
DevSecOps的优势 - 包括降低成本,提高客户价值和增加代码覆盖率 - 在DevSecCon的白皮书中有更详细的讨论。
但DevSecOps方法需要使用多种测试工具和工具类型,以便在整个过程中为应用程序安全提供应有的关注。让我们看看两种最常见的类型 - SAST和DAST。
SAST和DAST:为什么你需要两者
两种最常见的应用程序漏洞测试工具类型是静态应用程序安全测试(SAST)和动态应用程序安全测试(DAST)工具。
SAST工具从内部检查应用程序,查看源代码,字节代码或应用程序二进制文件以查找安全漏洞。另一方面,DAST工具从外部接近应用程序,模仿“机器人黑客”来发现漏洞。
有关SAST和DAST工具的优缺点,请查看我们最近关于应用程序漏洞测试软件的博客文章。
安全的软件开发生命周期需要全面的应用程序安全测试因此,您需要同时使用SAST和DAST工具 - 以及每种类型的多个工具。
市场上的每种工具都有其优点和缺点。您需要使用多种工具来确保从各个角度创建安全的应用程序。
有许多开源工具可以用很少甚至免费的方式来全面覆盖您的应用程序。但是多个工具可能难以管理。
数据过载以及如何有效地管理它
使用许多工具和不同类型的工具是在应用程序开发中产生某些挑战的必要之处。
每个工具都会生成一个充满潜在漏洞的报告(格式不同)。结果需要交叉引用以删除重复项,您需要确定哪些潜在威胁是真正可利用的漏洞。此外,您需要知道哪些是最大的威胁,以便您可以先解决它们。
然后是让开发人员关注这些问题的问题。开发人员不希望超出他们首选的工具包或停止修复潜在问题。只要代码有效(无论潜在威胁如何),他们只想继续构建。您如何跟踪是否有人正在处理某个问题以及是否/何时修复了问题?
有一种方法可以管理所有这些工具及其脱节结果,因此您可以简化应用程序安全测试过程 - 应用程序漏洞管理器。
Code Dx Enterprise就是这种工具的一个例子。它不是另一种测试工具 - 但它释放了您正在使用的测试工具的真正力量,并提供了从结果中获得真正价值的方法。您可以获得更好的漏洞覆盖率和更少的误报。
无成本和低成本开源工具的价值得以实现,因为这些工具的结果可以快速相关。这消除了手动清除这些结果的耗时,繁琐且容易出错的过程。
全面的应用程序安全测试过程变得可以实现。以下是应用程序漏洞管理器中要查找的一些功能:
- 重复数据删除 - 自动删除来自无数报告的重复结果。您将收到一份包含一组结果的报告。该工具适用于多种测试技术,包括SAST,DAST,IAST,第三方组件分析,威胁建模和人工审核。
- 补救管理 - 识别存在漏洞的特定代码行,并识别相邻的漏洞和漏洞。通过集中控制台,您可以分配,跟踪和监控修复进度。
- 工作流程集成 - 让开发人员关注安全威胁的好方法是什么,而不是让它成为开发环境的一部分?与Eclipse等流行环境集成使开发人员可以轻松解决问题。嵌入到持续集成环境中并与Jira问题跟踪工具集成的工具提供了额外的简化。与Jenkins构建服务器集成允许您在Jenkins中启动分析。
- 报告 - 各种报告可以轻松地对测试结果进行排序并跟踪补救措施的进展情况。报告修复问题所需的时间使您能够确保快速进行补救。
- 应用程序漏洞关联(AVC) - SAST工具可识别潜在漏洞,而DAST工具可识别哪些漏洞实际可利用。结合所有这些结果,您可以了解哪些威胁是真实的并且具有最高优先级
- 合规性检查 - 根据HIPAA,DISA-STIG和PCI DSS等法规自动检查您的代码库。标记违规行代码,并识别特定违规行为。建议遵守法规。
应用程序漏洞管理器不再使用各种工具和技术进行安全测试。您可以获得全面的安全保障,但不必浪费时间和资源对结果进行分类,识别真实威胁,并跟踪它们是否已修复。
安全性受到DevSecOps的关注。你保持敏捷,而不是淹没在结果的海洋中。
原文:https://codedx.com/how-to-manage-sast-and-dast-results-code-dx-blog/
本文:
讨论:加入知识星球或者小红圈【首席架构师圈】
- 40 次浏览
【安全运营】IAST,RASP和现在的HAST如何增强应用程序安全性
信息安全漏洞继续成为头条新闻。 2017年和2018年初,Equifax甚至IRS等几个主要组织成为利用安全漏洞的黑客的牺牲品。
攻击速度很快,从发布常见漏洞和暴露(CVE)的一天开始。有时,零天。你如何保护自己?
应用程序安全性测试至关重要,必须正确完成。这意味着遵守推荐的应用程序安全准则,并使用最新的工具和技术。
到目前为止,您很可能熟悉应用程序安全性的两种最突出的技术方法,其中包括引人注目的首字母缩略词:SAST,用于静态应用程序安全测试,检查应用程序的已知编码缺陷实例的源代码;动态应用程序安全测试(DAST)会在您的应用程序运行时探索它,以寻找黑客可以从外部找到的相同缺陷。
在这里,我们仔细研究三种新兴的应用程序安全工具,通过在代码中引入工具来进一步实现这一点 - 交互式应用程序安全测试(IAST),运行时应用程序自我保护(RASP)以及Code Dx产品独有的新技术我们称之为混合应用安全测试(HAST)。
每个人都使用类似的技术在您的应用程序中插入特殊代码 - 我们称之为“检测”您的代码,宇航员的工具监控方式以监控他们的健康状况 - 为应用程序安全测试提供非常不同的好处。您需要了解每个之间的差异,以便您可以正确利用它们并创建一个合理的应用程序安全策略。
互动应用安全测试(IAST)的兴起
IAST结合了检查代码的SAST理念和正在运行的应用程序的DAST视图,但它们在应用程序运行时同时执行。虽然SAST工具谈到从“内部”测试应用程序和从“外部”测试DAST工具,但IAST工具谈到“从内到外”进行测试。
IAST工具将应用程序代码(称为“代理”)安装到应用程序中,以便在应用程序运行时监视应用程序,扫描安全漏洞。代理收集应用程序中的数据,可以识别SAST和DAST工具遗漏的安全漏洞。
IAST工具的好处包括:
- 报告的误报较少
- 提供更全面的应用程序代码覆盖,因为它在应用程序中工作。它涵盖:
- 整个应用程序源代码
- 运行时控件
- 配置信息
- 第三方库和框架
- HTTP请求
- 数据库查询
- 后端连接信息
- 很容易融入开发过程
- 提供可扩展性
- 为开发人员提供即时反馈,以便立即解决问题
IAST工具的缺点是:
- 它们会对应用程序性能产生负面影响:因为它们会为代码添加工具,所以它们会改变代码的执行方式。
- 它是一种较新的技术,因此可能仍会出现其他问题或缺点。
然后是运行时应用程序自我保护(RASP)
最近的一项发展是RASP - 运行时应用程序自我保护。据预测,在2018年至2022年期间,RASP的全球市场将以近50%的复合年增长率(CAGR)增长。
顾名思义,RASP技术在应用程序运行时为其提供安全保护 - 与IAST提供的检测相反。 RASP通过在应用程序中安装代理来利用与IAST相同的技术;不同之处在于代理的使用方式。 IAST工具会查找安全漏洞,而RASP会监视应用程序是否存在攻击,并在感知到攻击发生时保护应用程序免受攻击。
RASP不会影响应用程序的设计。它为部署中的应用程序添加了一层保护,检查正在执行的每条指令,并确定任何给定的指令是否实际上是攻击。
它可用于简单诊断或自我保护:
- 诊断使用意味着发现攻击时会发出警报或警报。
- 自我保护意味着它实际上会停止导致攻击的执行。
RASP的优点是:
- 在应用程序运行时为您的应用程序提供额外的保护层。它被许多人视为比旧的Web应用程序防火墙(WAF)更好的保护层,因为RASP存在于应用程序内而不是外部。
- 适合更快的开发周期。
- 允许您巡视意外输入。
- 如果发生攻击,提供有关攻击的更详细信息 - 这意味着您可以更快地解决问题。
这种新兴技术的缺点是:
- RASP工具位于应用程序服务器上,从而降低了应用程序性能。
- 由于法规或内部策略阻止安装其他软件或锁定的基础架构(如平台即服务(PaaS)),并不总是可以在生产中部署RASP代理。
- 使用RASP会导致错误的安全感。您可能会想,“我们不需要担心应用程序安全性,因为我们的运行时应用程序自我保护会让我们保持安全。”事实并非如此。如果RASP确实发现问题,则仍需要修复,这可能意味着在您处理应用程序时使应用程序脱机。
RASP不会取代应用程序安全性测试。它是一种更新的技术,可以增强标准的应用程序安全测试过程,但不能防范所有漏洞。
现在,混合应用安全测试(HAST)
IAST和RASP是很有前景的技术,但正如所指出的那样,它们都会对它们在为用户运行时如何影响应用程序产生问题。为了在开发过程中获得运行时知识的安全性好处,但不会影响用户,我们设计了一种混合方法,在动态测试期间使用代理技术获取运行时代码执行洞察,并结合这些见解通过静态测试,可以更快,更轻松地找到并修复攻击者最容易访问的漏洞。
我们已经将这种混合应用程序安全测试(HAST)称为整体应用程序安全测试过程的一部分。 HAST合并并关联SAST工具和DAST工具的结果,将您的工作重点放在最重要的漏洞上,并为应用程序安全测试带来巨大好处。
SAST工具可识别潜在的漏洞。结果需要与DAST工具发现的问题交叉引用,以确定潜在的漏洞是否是可利用的威胁。
HAST实现了这一点,结合并关联了两种工具的结果。您可以确定哪些漏洞真正可以被利用,并且应该位于补救列表的顶部。
通过在应用程序中安装代理,HAST再次使用与IAST和RASP相同的技术。在进行DAST渗透测试时,代理在正在运行的应用程序中工作,并确定哪些DAST发现与哪些SAST结果相关联。
最新版本的Code Dx Enterprise现在提供HAST。有关这项新功能的更多信息即将推出。
这些新的应用程序安全测试工具可以更好地进行应用程序安但它们并不能取代SAST和DAST工具。
正确的应用程序安全测试策略使用SAST,DAST,IAST,RASP和HAST来识别漏洞,确定漏洞的优先级,并提供额外的防御层保护。
但您仍需要修复找到的问题,这需要修复过程。使用正确的工具可以为您提供全面的覆盖,并通过自动关联结果来简化整个过程,以帮助您识别需要立即关注的结果。
随着新工具和技术的出现,您需要自学,了解如何确保应用程序的安全。
原文:https://codedx.com/how-iast-rasp-and-hast-enhance-appsec-code-dx-blog/
本文:
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 211 次浏览
【安全运营】完美结合:漏洞评估和渗透测试(VAPT)
百分之百 - 所有由Positive Technologies测试的应用程序都存在某种漏洞。您可能会想,“是的,但其中有多少是真正的,关键的漏洞?”嗯,94%的Web应用程序测试包含高严重性的软件漏洞。这些相同应用程序中有85%包含至少一个已确认的可利用漏洞。
这些并不令人鼓舞 - 实际上,它们非常令人恐惧。这些应用程序对我们有多少数据?但这些数字也表明应用程序漏洞中的一个重要区别 - 潜在威胁与可利用威胁。
你如何轻松区分这两者?答案很简单 - 漏洞评估和渗透测试(VAPT)。
简介:VAPT的背景故事
漏洞评估和渗透测试(VAPT)起初可能听起来像AppSec场景的新术语,但实际上,它只是两个常见(非常重要)应用程序安全活动的组合。 VAPT通过渗透测试将漏洞评估测试结合在一起。
漏洞评估是使用各种工具和技术检查您的应用程序,以发现潜在的漏洞。这是通过应用程序安全测试工具(在下面的资源部分详细介绍)完成的。
威胁作为流程的一部分进行识别,分类和优先排序。不同的工具可以更好地识别不同类型的漏洞,因此重要的是不要仅依靠一种工具进行漏洞评估。
漏洞评估工具非常适合查明可能使您的应用程序受到攻击的威胁。他们确定了理论上的漏洞。
但是,您如何知道这些威胁是否真的可以利用?在现实世界中,攻击者是否可以通过这些漏洞访问您的应用程序?这是渗透测试变得非常宝贵的地方。
渗透测试(通常称为笔测试)是主动攻击您的应用程序以确定是否可以实际利用潜在漏洞的过程。通俗地说,它是针对您的应用程序的模拟攻击(通常手动完成,但我们建议使用自动选项),可以针对应用程序中的代码和系统执行,例如API和服务器。
渗透测试有几种方法可以采用:
- 外部 - 攻击主要针对外部用户和攻击者可见的系统和资产。
- 内部 - 可以从防火墙后面攻击应用程序。
- 盲目 - 这模拟了实时攻击,测试人员只使用公司名称进行武装。
- 双盲 - 类似盲目测试,但安全团队没有被告知模拟,测试他们响应实时攻击的能力。
- 针对性 - 笔测试的培训方法,其中笔测试者和安全团队通知对方,以了解攻击者如何进入应用程序以及安全可以采取哪些步骤来进行强有力的防御。
VAPT强调了重要的一点,即没有一种类型的测试可以提供全面的应用程序安全性。漏洞评估和渗透测试都是必要的。实际上,在一种类型的测试中减少或减少打开会使应用程序出现漏洞。
适当的VAPT方法有几个步骤,例如:
- 规划范围 - 确定将在测试中包含哪些系统和代码以及将使用哪些测试方法。
- 数据收集 - 收集有关攻击目标的数据。
- 漏洞检测 - 识别应用程序的潜在漏洞和威胁。使用漏洞扫描程序等工具发现目标上的其他信息。
- 获取和维护访问权限 - 笔测试人员试图访问应用程序,看看他们是否可以进入。一旦进入系统,测试人员就会确定他们可以被忽视多长时间以及他们可以造成多大的伤害。
- 覆盖轨道 - 对应用程序所做的任何更改都是隐藏的,因此攻击正在进行中并不明显。
- 报告 - 必须分析和记录VAPT测试的结果。这包括需要解决的威胁的建议和优先级。
完美结合:VAPT的好处
- 全面的应用程序安全性 - 您可以放心,您的应用程序将在内部和外部彻底检查不同类型的漏洞。
- 信誉管理 - 受损的应用程序对业务不利。恢复通常是漫长而缓慢的道路。 VAPT降低了攻击发生的可能性。
- 数据安全性 - VAPT可创建更安全的应用程序,提高数据安全性并保护您的知识产权。
- 改进的合规性 - VAPT测试可确定您的应用是否符合某些行业标准和法规,例如PCI-DSS和ISO / IEC 27002.如果您想避免昂贵的罚款,这是必要的。
- 应用程序安全性内置于流程中 - 使用VAPT在开发期间测试应用程序使安全性成为流程的一部分。这是构建安全应用程序的有效且负责任的方式。替代方案(威胁被利用后的昂贵修复)浪费资金和资源。
资源:VAPT测试工具
漏洞评估工具
- 静态应用程序安全性测试(SAST)工具 - 自动检查潜在漏洞的源代码,字节代码和应用程序二进制文件。例子包括Veracode和CodeSonar。
- 动态应用程序安全性测试(DAST)工具 - 模拟真实的攻击者,从外部接近应用程序以确定哪些威胁可被利用。正在运行的应用程序需要使用这些工具。
- 交互式应用程序安全性测试(IAST)工具 - 通过在应用程序运行时使用应用程序内部的信息来识别漏洞,从而结合SAST和DAST工具的优势。需要注意的是,这些工具会对应用程序性能产生负面影响。提供IAST工具的供应商包括Acunetix和Contrast Security。
- 软件组合分析(SCA)工具 - 分析应用程序中使用的第三方源代码,库和框架,以识别安全漏洞和许可问题。当然,这意味着您需要拥有所使用的所有第三方组件的更新和准确的列表。例子包括Black Duck和Sonatype。
渗透测试工具
- Burp Suite - 用于Web应用程序安全性测试的图形工具,可以检测SQL注入,跨站点脚本和其他漏洞。有免费版本和更强大的付费选项。
- OWASP Zed攻击代理(ZAP) - 一款免费工具,可帮助笔测试人员识别漏洞。
- 代码脉冲 - 一种开源工具,可在笔测试期间自动检测覆盖范围。在执行代码时,应用程序攻击面的可视化表示会实时更新,通知笔测试人员应用程序的哪些部分已经过测试。
- 攻击面检测器 - 一种开源工具,可自动识别所有未链接或隐藏的端点,其参数和数据类型。然后,可以使用此数据预先播种OWASP ZAP或Burp Suite(均在上面列出)。 Attack Surface Detector既是标准命令行界面,也是ZAP和Burp Suite的插件。
VAPT工具
考虑使用上述所有工具来管理漏洞评估和渗透测试可能看起来势不可挡。幸运的是,还有另一种工具可以帮助理解无数的结果。
应用程序漏洞关联(AVC)工具简化了管理多个工具结果的过程。市场上更强大的AVC工具甚至通过关联静态和动态测试结果提供支持VAPT的功能。
好处包括:
- 混合分析 - 结合SAST工具和DAST工具的结果,确定哪些潜在漏洞实际可利用。这增加了VAPT测试的全面性,并提供了潜在漏洞可利用的证据。这些是您首先需要修复的漏洞。
- 升级 - 用户可以升级发现并记录漏洞的利用方式。
- 重复数据删除 - SAST,DAST,IAST,SCA和笔测试工具的结果与一个报告相关联。删除重复项,使结果更容易消化。手动测试的结果也可以输入到系统中,因此这些结果包含在重复数据删除中。
- 补救管理 - 标记包含漏洞的特定代码行,使补救更容易。可以通过中央控制台为团队成员分配任务,并使用跟踪选项确保及时纠正问题。
- 合规性检查 - 根据HIPAA,DISA-STIG和PCI-DSS等法规自动检查您的代码库。标记违规行代码,并识别特定违规行为。
- 工作流集成 - 许多AVC工具支持集成到开发人员环境中,例如Eclipse和Jenkins。开发人员会收到当前系统中的漏洞警报,而不是引入另一个管理工具。
通过VAPT进行漏洞评估和渗透测试的结合是强大而合乎逻辑的。可能的威胁列表缩小到真正的罪魁祸首,因此您知道在哪里集中注意力以获得最大的应用程序安全性。
原文:https://codedx.com/the-perfect-union-vulnerability-assessment-and-penetration-testing-vapt/
本文:http://pub.intelligentx.net/node/472
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 311 次浏览
【应用安全测试】每个SAST工具仅发现代码中大约14%的漏洞
应用程序开发过程的一个基本要素是扫描软件以发现潜在的漏洞。静态应用程序安全性测试工具因返回大量结果(通常是数千个,甚至是相对较小的应用程序)而臭名昭着,这可能会让开发人员感到不堪重负。但无论他们对结果如何看待,软件开发人员必须明白,只运行一个应用程序安全测试工具 - 即使是市场上最好的 - 他们也缺少代码中的大多数弱点。
一个工具只涵盖了冰山一角。单个分析工具可能存在数千个缺陷,这可能导致错过严重的缺陷,可能会使有价值的数据面临被利用的风险。
一个SAST工具仅提供14%的覆盖率
根据美国国家安全局(NSA)保证软件中心(CAS)的一项研究,平均静态代码分析工具涵盖了13个弱点类别中的8个(例如缓冲区处理,文件处理,初始化和关闭以及数字处理) ,这是61.5%。该研究还发现,平均工具仅涵盖13个弱点类别中每个缺陷的22%。如果缺陷的百分比乘以所涵盖的弱点类别的百分比,则平均工具的总覆盖率仅为14%。
对于许多软件开发人员来说,这应该是一个令人大开眼界的统计数据,他们认为他们的漏洞扫描程序覆盖范围更广。缺少应用程序代码中80%以上的弱点,任何组织都不应该接受。
其他研究支持这些发现。一项研究评估了三种商业静态代码分析工具,并确定它们在检测应用程序漏洞时的性能接近或低于平均值。对九种工具的另一项评估发现平均回忆率为0.527,精度为0.7,而另一项评估的结果确定任何一种工具的最高回忆率为18.4%。
除了发现每个分析工具都未能报告所研究的大部分缺陷之外,NSA CAS和后续研究发现这些工具在各种语言和弱点类别上表现不同。
SAST弱点
鉴于这些研究的结果,我们认为必须牢固地了解静态应用程序安全测试工具的一般弱点。这些知识可用于确保为应用程序安全性测试选择正确的SAST工具组合。
SAST的弱点包括无法:
- 解释结果 - 您仍然需要确定一个发现是否是真正的积极因素以及对您的应用程序的影响。
- 认识到应用程序设计或体系结构中的缺陷。
- 识别新类型的错误。这可能通过一些自定义来实现,但这需要团队的一些额外工作。
- 证明应用程序代码没有缺陷。换句话说,仅仅因为给定的SAST工具没有发现问题,并不意味着它不存在。
这就是采用组合方法并使用多个SAST工具非常重要的原因。事实上,研究发现可以将补充工具结合起来以获得更好的结果。
两个或更多工具不仅会覆盖更大的代码区域,而且每个工具都专注于不同的弱点类和不同的语言,这消除了工具之间的大量重叠。当存在重叠时,这是一个强有力的指标,表明已识别的缺陷不是误报,开发人员可以专注于确保这些缺陷得到修复。
不仅仅依赖SAST工具也很重要。使用其他类型的工具,例如动态应用程序安全性测试(DAST)工具和交互式应用程序安全性测试(IAST)工具,以及手动代码审查,以实现全面的应用程序安全性。
如何管理多个应用程序安全测试工具
使用多个工具确实带来了挑战,即设置和运行工具所需的额外时间,比较结果以及添加更多工具所需的成本。比较结果可能是艰苦的,因为每个工具都会产生一系列具有自己的命名约定和严重等级的弱点。
这是我们开发Code Dx的原因之一:识别所使用的各种工具的重叠。无论是使用商业扫描程序,开源漏洞工具还是两者的组合,Code Dx都会显示每个工具的结果,并确定每个工具发现的漏洞(并且由多个工具发现)。
Code Dx应用程序漏洞管理器将商业和开源工具的结果进行关联和规范化,以提供一组统一的结果,从而更好地覆盖源代码中的潜在漏洞,并更好地评估组织的整体企业风险。
重复数据删除,补救管理,报告和合规性检查在一个简化的工具中处理。工作流集成选项允许您的开发人员在解决应用程序漏洞问题的同时保留其首选环境 - Eclipse,Jira,Jenkins和其他环境。
此工具最有价值的好处之一是应用程序漏洞关联(AVC),也称为混合分析。这是指SAST结果(识别潜在漏洞)与DAST结果(确定哪些威胁实际可利用)的组合。这使您可以确定代码中存在哪些威胁,并且可以被外部攻击者利用,因此您可以先解决这些威胁。
不要满足于14%的覆盖率;这会使您的应用程序和您的声誉面临严重威胁。全面的方法涉及多个SAST,DAST和其他应用程序安全测试工具,可以提供最安全的应用程序,其优势将逐渐降低到您的底线。
幸运的是,使用多个工具比看起来更容易。 Code Dx简化了应用程序安全测试过程。您的团队可以使用所有必要的工具来全面覆盖您的应用程序代码,而无需管理多个工具和他们提供的脱节结果。
原文:https://codedx.com/14-percent/
本文:
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 42 次浏览
【应用安全测试】白盒,黑盒和灰盒漏洞测试:有什么区别,为什么重要?
2017年出现了创纪录的安全漏洞数量,截至第三季度末已报告超过16,000个漏洞。这比2016年的总和还要多。虽然一些组织正在迅速解决这些应用程序安全风险,但其他组织却未能这样做。 SANS最近的一项调查发现,10%的企业根本没有测试他们的安全应用程序,另外24%的企业每年只测试一次或更少。仅有12%的组织定期执行应用程序安全测试。
为什么企业忽视应用程序安全测试?快速开发周期是一个主要因素,应用程序安全测试被视为阻碍开发和部署的障碍。 2017年关于移动和物联网应用安全测试的报告发现,高达75%的应用安全专业人员感到有压力要求以安全为代价来推迟发布。
这些统计数据之间的二分法令人震惊。企业需要更加关注应用程序安全性测试,即使这意味着放慢速度。在应用程序部署之后修复漏洞会给企业带来更多时间和资源,更不用说负面宣传,收入损失,客户数据和信任丢失,声誉受损,甚至可能采取法律行动应该利用这些漏洞。
了解可以采用的不同方法进行应用程序安全性测试可以帮助您制定可提供最大投资回报率的策略,平衡安全性的提高以及所需的额外时间和资源。
有三种应用程序安全测试,通常称为黑盒安全测试,白盒安全测试和灰盒安全测试。了解每种类型之间的差异将有助于您形成一个强大的应用程序安全性测试计划,从而降低您面临潜在威胁的可能性,并最大限度地利用资源,资金和时间。
黑匣子安全测试
黑盒安全测试模仿黑客的行为,从外部攻击应用程序。在这样做时,它会测试应用程序的功能。它是基于攻击者不了解应用程序内部工作原理的假设来执行的:它将应用程序视为“黑盒子”,其内容是您无法看到的,就像黑客无法看到您的应用程序一样。
黑盒安全测试可以模仿各种技能水平的黑客,例如:
- 脚本小子(滑动) - 未经训练的个体(“小子”)使用由其他人开发的程序或脚本来攻击应用程序,并扫描已知的漏洞。
- 中级黑客 - 拥有更多关于开发,系统和网络的知识的个人,因此可能造成更大的破坏。
- 精英黑客 - 更有可能由民族国家赞助的个人。他们有更多的时间和资源来投入黑客攻击。
此测试会查找已知漏洞,弱访问控制以及应用程序中的弱防御机制。要彻底,测试可能发挥作用的所有变量和场景非常重要。
黑盒安全测试的优点是:
- 此测试可以比白盒漏洞测试更快地完成,因为它的范围更加有限,只能从应用程序外部进行攻击。
- 虽然这取决于具体的应用和测试范围,但成本可能更低。
缺点包括:
- 它并不全面,因为它只是从外部进行测试。
- 如果没有明确指导特定测试的区域和/或漏洞,测试用例可能难以设计。
- 如果您想要彻底,可能需要花费大量时间来尝试不同的场景和用例。黑客通常比你手上的时间更多,所以你不能总是预见到他们可能会尝试的一切。
白盒安全测试
白盒安全测试是基于对应用程序的所有知识,测试应用程序的内部工作而执行的。通常可以访问完整的源代码,因此源代码扫描和评论通常作为测试过程的一部分。提供对应用程序的内部(本地)完全访问,包括登录凭据和完全身份验证。白盒安全测试应在应用程序投入生产之前完成,因此可以在部署之前识别和纠正漏洞。
白盒漏洞测试有几个优点:
- 从源代码到应用程序架构和设计,发现各处潜在的漏洞
- 提供应用程序安全性的全面测试
- 可以在开发过程的早期开始
此测试的缺点是:
- 发现的任何潜在漏洞都需要通过黑盒测试进一步测试,以确定它们是否实际可利用,这需要额外的时间。采取此步骤可帮助您确定修复工作的优先顺序。
- 这种类型的测试更长,减慢了开发过程并与快速开发生命周期相冲突。
- 由于需要时间和高技能资源,它更昂贵。白盒安全测试需要了解应用程序不安全的原因,读取代码的能力以及软件架构中的安全风险。
灰盒安全测试
顾名思义,灰盒安全测试是白盒和黑盒测试的结合。当您需要平衡时间,成本和影响时,这是最理想的方法。
根据应用和测试目标,可以以各种方式使用灰盒安全测试。例如,它可以通过测试白盒测试中发现的潜在漏洞的可利用性来执行。
此测试的基础是黑客对应用程序的内部工作方式知之甚少,包括但不限于以下方案:
- 黑客对应用程序的数据流和体系结构有着高度的了解。
- 黑客可以访问部分源代码或编译的二进制文件,并且可能知道应用程序正在使用的语言和特定技术。
- 黑客可能拥有他/她可以登录的用户或管理员帐户。
这些都不是无理的假设:经验丰富的攻击者有办法发现这样的事情。
然后创建场景以测试具有更高优先级或关注的特定区域,模仿可能对应用程序的内部工作有部分了解的真正黑客。在优势方面,灰箱安全测试:
- 以更有针对性的方式攻击应用程序的某些部分
- 提供黑盒和白盒测试的好处
- 比白盒安全测试花费更少的时间,使其更好地平衡应用程序安全测试的时间,精力和成本
- 为时间和资源提供最佳投资回报率
- 更好地表示一个确定的黑客,他可能至少对应用程序的内部工作有一些了解,并有更多的时间专注于攻击,可能会研究公司,开发人员和应用程序。
当然,灰盒安全测试有一些缺点:
- 它不会涵盖应用程序的所有方面,因为这将非常耗时。
- 它缺乏白盒测试提供的源代码的完整覆盖。
- 测试用例可能难以设计。
为什么这一切都很重要?
了解三种类型的应用程序安全性测试之间的基本差异以及每种方法在提高应用程序安全性方面的作用非常重要。拥有多个选项有助于制定最适合您项目预算和时间表的方法。
在理想的世界中,企业将采用混合方法,根据特定应用和可用资源采用某些类型的测试。
为了帮助制定应用程序安全测试策略,请记住每种测试的最佳用途:
- 黑匣子安全测试 - 模拟脚本“小子”(没有大量时间,资源或技能的攻击者)的短期黑客攻击。
- 白盒安全性测试 - 确保您的开发人员不会在应用程序中引入漏洞
- 灰盒安全测试
- 模拟具有更多知识和技能的黑客攻击
- 模拟来自内部威胁的攻击
- 测试白盒测试中发现的潜在漏洞
了解所有这三种风格并利用每种风格的优势可帮助您创建更具弹性的应用程序安全配置文件。花时间预先制定应用程序安全测试计划,并将其纳入开发过程,可以使您的应用程序无法应对当今市场中安全漏洞的增加。
原文:https://codedx.com/black-white-and-gray-box-vulnerability-testing-code-dx-blog/
本文:http://pub.intelligentx.net/node/478
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 282 次浏览
【应用程序安全测试】在应用程序安全测试中节省时间的8种方法
全面的应用程序安全测试所需的成本和时间通常会阻碍企业实施适当的漏洞测试和修复策略。当然,那是在惹麻烦。幸运的是,该流程可以简化,使您能够以更有效和及时的方式进行应用程序安全测试。
我们将回顾您可以做的八件具体事情,立即开始,这将有助于您的appsec测试更顺利,更好的结果。
应用安全测试:你在浪费时间吗?
应用程序安全性测试很重要有三个原因:
- 无论您认为代码的安全性如何,应用程序始终都存在漏洞。
- 应用程序安全性测试是在外部黑客暴露这些漏洞之前识别这些漏洞的主动方法。
- 在部署之前识别漏洞可以节省大量的时间,金钱和资源。在应用程序掌握在用户手中之前,可以解决问题;如果在发布后发现问题,您将需要向用户群发送更新,并且您可能会遭受声誉损失和/或诉讼风险。
因为测试和修复漏洞需要时间,所以效率越高越好。您希望从测试中获得最相关的结果,误报率和重叠结果的数量最少。重叠结果 - 由多个工具识别的结果 - 非常常见,因为没有一个工具可以找到所有错误。大多数开发人员使用多个工具。这会自动引入低效率,因为每个工具都有自己的用户界面和报告方法。您的开发人员必须学习如何使用多个工具,但结果和建议通常以不同方式呈现 - 并且经常重叠。
如何简化应用程序安全测试
以下是简化应用程序安全性测试过程的“最佳实践”,因此可以更轻松地集成到开发过程中。
1.利用应用程序漏洞关联(AVC)工具 -
AVC工具汇总来自多个工具的数据,对结果进行重复数据删除。您可以使用过滤器来关注最关键的区域。您可能已经定义了各种严重性级别,或者您可能会关注OWASP指南。 AVC工具确定安全范围的差距。它们还使结果和严重程度标准化。例如,Code Dx是一个AVC工具,允许开发人员使用一种通用语言,可以在组织内或从一个项目到另一个项目进行自定义。用户可以使用SQL Injection的默认描述以及引用和补救建议,或者为其组织定制指令性指南 - 可能使用内部门户链接或内部软件库来帮助解决安全问题。
2.将漏洞发现与一个有凝聚力的报告相关联 -
必须将调查结果与多种类型的测试和技术相关联,包括SAST,DAST,IAST,组件分析,手动测试,代码审查和威胁建模。这可能是一项非常耗时的工作,并且随着开发人员以各种格式和多种来源接收信息,使补救更加具有挑战性。相关工具通过编译,重复数据删除和分析各种测试方法的结果来简化这一过程。开发人员会收到一份清晰且易于理解的报告。这是对多个,重叠甚至相互冲突的报告的巨大改进。
3.使用应用程序安全性编排 -
此类工具允许您在一个位置管理多个appsec工具。您可以轻松地将一个供应商换成另一个供应商而不会中断工作流程。 Code Dx通过其REST API与Systems Development Life Cycle(SDLC),Jenkins构建服务器插件和其他构建服务器集成,使Code Dx易于在现有管道中使用。您还可以通过自动配置自动合并某些SAST工具。该程序根据正在测试的应用程序确定应运行哪些工具。
4.加快开发补救和协作 -
如果安全分析师和开发人员通过测试工具连接,他们可以就问题和进展进行沟通,测试和开发将成为一个更有效和集成的过程。这样做的一种方法是使用Code Dx之类的工具,它可以自动在Jira中输入已识别的威胁,使开发人员了解最新的潜在漏洞。 Code Dx还提供分配任务,跟踪进度和发表评论的功能。用户可以对漏洞采用一致的描述;所有工具的输出都将使用相同的术语。您还可以自定义术语以匹配组织的语言。
5.将数据存储在集中式存储库中 -
将所有应用程序安全信息存储在一个中央,安全的位置,使组织内的所有相关方都可以访问数据。用户可以搜索和排序结果,分配任务,甚至可以运行有关漏洞的报告。
6.保持合规 -
确保您的应用程序符合任何相关法规保护您的声誉,并防止您因违反任何违规行为而被罚款。使用可根据常见合规性标准自动检查漏洞的工具。 Code Dx为许多标准做到了这一点,包括OWASP Top 10 Mobile,HIPAA,DISA安全技术实施指南,NIST 800-53和支付卡行业数据安全标准。
7.与集成开发环境(IDE)集成 -
通过在开发过程中识别和解决威胁,将应用程序安全测试与IDE集成可以节省时间。例如,如果您的开发人员在Eclipse或Visual Studio中工作,他们可以解决测试期间从此界面引发的问题。他们不需要切换到其他工具。他们可以将补救措施纳入当前的工作环境。
8.提供适当的安全培训 -
应为参与开发和测试过程的所有人员提供全面培训。应明确界定角色和责任。培训应保持新鲜并不断更新,以掌握最新的威胁,确保测试和解决过程更加高效。
应用程序安全性测试不一定非常困难。使用多个工具是必要的恶魔,但有一些方法可以对结果进行排序,整理和分析。简化流程意味着您可以快速识别问题,适当地解决问题,并通过补救流程跟踪问题。所有这些都可以在预生产环境中高效完成,保护您的资产和声誉。
原文:https://codedx.com/streamlining-application-security-testing-code-dx-blog/
本文:http://pub.intelligentx.net/node/473
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 48 次浏览
微服务测试
- 65 次浏览
【API测试】API测试自动化教程:循序渐进指南
贵公司是否为其软件编写API? 如果答案是肯定的,那么你绝对需要对它进行测试 - 幸运的是,本教程逐步解释了如何使用Postman,Newman,Jenkins和qTest Manager等工具进行自动API测试。
但首先,让我们来看看这块土地。事实证明,您的软件API实际上是您可以测试的应用程序中最重要的部分,因为它具有最高的安全风险。
您的软件API实际上是您可以测试的应用程序中最重要的部分,因为它具有最高的安全风险
例如,容纳客户端软件的浏览器或应用程序可以防止很多糟糕的用户体验,例如发送100个字符的用户名或允许奇怪的编码字符输入,但您的API是否也会阻止这些事情?如果有人开始猜测其他用户的“独特”令牌,软件是否会回复真实数据?它是否有Apache错误消息,其中包含正在运行的服务版本?如果这些问题的答案都是肯定的,那么就存在一个相当大的安全漏洞。或者,如果有人要破解API怎么办?他们可以得到生产数据,他们可以比特币赎回服务器,或者他们可以隐藏在机器上,直到有趣的事情发生。最重要的是,使用API时的风险远高于应用程序用户界面中的错误 - 您的数据可能存在风险,并且通过代理可能会影响您的所有用户数据。
幸运的是,API测试不仅是对您的应用程序进行的最重要的测试,而且它也是最简单,最快速的执行。这意味着没有理由你不应该有一个广泛的API测试套件(并相信我,有一个将帮助你在晚上睡得更好)。使用持续集成的API测试套件,您可以轻松地:
- 无论托管在何处,从AWS Lambda到本地计算机,都要测试所有端点
- 快速确保所有服务按预期运行
- 确认您的所有端点都受到未经授权和未经身份验证的用户的保护
- 观察您的测试执行“神奇地”填充在您的测试管理工具中
那么你如何将所有这些付诸行动呢?你来对地方了。继续阅读有关如何设置Postman和Newman的逐步API测试教程,如何从Jenkins执行测试,以及如何将所有这些测试结果集成到qTest Manager等测试管理工具中。
让我们开始吧!
Set Up Postman
1)第一件事是第一件事:你需要下载Postman。
它是免费的,很有趣,适用于Mac,Windows和Linux机器。注意:如果您拥有更大的团队并经常更新服务和测试,您可能需要考虑Postman Pro(但您可以随时决定升级)。
2)确保您的应用程序的API文档很方便。
对于本演示,我将使用qTest Manager API,因为它简单明了。如果你想逐字尝试这些演示,你可以在这里免费试用qTest Manager。您还可以使用大量可在线使用的API(如果您正在寻找其他地方,我建议您从AnyAPI开始)。
3)接下来,提取您正在使用的API的登录调用文档(您可以在下面找到qTest Manager的文档)。该文件应包括:
- Method (POST/PUT/GET/DELETE/etc)
- URI (/oauth/token which will follow the URL for the instance of qTest you’re using)
- Headers
- Body
在此示例中,登录调用需要x-www-form-urlencoded内容类型标头。您只需在Postman中选择它,它就会自动添加相应的标题。选择此选项后,Postman将允许您为授权类型,用户名和密码输入名称/值对。注意:每次拨打电话时,请确保您的网络协议是HTTPS,否则您通过互联网传递的所有数据都是明文,没有人想要这样。
4)如果您正在使用qTest Manager,请继续构建测试并写出您想要在测试用例中测试的内容。完成后,我们将通过映射测试用例ID将测试用例链接到自动API测试。通常,在测试用例管理工具中首先写出测试应该做的事情是编写自动化测试用例的一个很好的过程。
5)构建测试并编写您希望测试用例的内容后,将该工作链接到您的完全可跟踪性要求,然后将自动测试执行挂钩到该测试用例。如果您使用的链接到JIRA的qTest Manager等工具,您将在JIRA中看到所有匹配要求的文本执行。很酷,嗯?
6)现在让我们第一次调用登录端点,以便我们可以获得一个令牌(我们稍后会将令牌传递给后续调用,以便API知道我们已经登录)。查看登录文档,我看到这是一个POST请求。如果是GET,您将通过URL传递您的用户名和密码。为确保一切顺利进行,请确保您具有以下设置:
- Method: Post
- URL: your http://your.qTestURL/oauth/token
- Click on the Body tab and set the request body to x-www-form-urlencoded (these are just different standard ways to pass data in the body of your HTTP request) – and clicking the radio button just sets an HTTP header field Content-Type to be application/x-www-form-urlencoded.
- Now set 3 name/value in the Body:
- grant_type : password
- username : your qTest username
- password : your qTest password
请注意API文档中有关未填写密码的命令,在Postman提供的字段中的名称/密码区域中。
7)你的设置是否匹配?大!现在您有一个有效的API调用。我们将它保存到邮递员集合中,以便我们以后可以重复使用它。要创建新的Postman Collection,只需点击左侧面板中加号的文件夹图标即可。
创建集合后,您可以通过单击屏幕右上角的“保存”按钮来保存呼叫(标准操作系统快捷方式也可以)。我使用qTest中的测试用例ID命名了我的API调用。这将允许我映射我的测试用例,以便每次运行此API调用以及其余测试时都可以跟踪。
8)在我们实际编写测试之前再多一步,因为我们需要对HTTP响应做一些事情:
- Verify the status code is 200 (OK)
- Verify that you get back a non-empty access token
- Verify that your scope is accurate
请注意,我们并不关心其他字段 - 它们对您测试您已登录并不重要。
9)现在是时候编写第一个测试了!小心不要让你的测试变得脆弱 - 要清楚你正在测试的是什么以及为什么要测试它。
10)接下来,让我们编写另一个测试,将测试用例添加到现有项目中。首先,我们需要登录并存储我们的令牌。我们将创建一个环境变量并将其命名为“access_token”:
存储此访问令牌的好处是您现在可以在后续调用中使用它。 这意味着您可以自动执行测试,而无需每次都手动获取登录令牌。 优秀! 在下一个调用中,您将看到使用双花括号{{access_token}}的令牌。
11)让我们看一下添加测试用例的文档,您可以在这里找到:
然后继续为您的新测试用例创建一个位置:
12)现在让我们创建一个新的POST请求来添加一个测试用例。 URL(路径)中有一个名为{project}的变量。 要填写此变量,我们需要在qTest中获取项目的ID,我们可以从qTest URL获取该ID。 在这种情况下,你可以看到它是45625:
我们还需要在字段中填写这些字符串:
- name: Testing Create Test Case
- description: This test case was created by the API test
- parent_id: 2656708
请注意,parent_id是我们刚刚为这些测试转储的文件夹/模块的ID。该ID可以在该测试模块页面的URL中找到。
13)接下来,我们必须将注意力转向我们拥有的两个数组属性。对于test_steps,这将是一个JSON数组,它是两个方括号之间的逗号分隔的JSON对象列表。每个对象都是一个步骤,数组字符串中的每个JSON对象都应该在引号内。注意不要从Microsoft Word文档或其他来源复制“漂亮的引号”,以进一步美化您的文本。
Test_steps:
“test_steps” : [{
“description”: “Step 1 – open login page”,
“expected”: “login page opens, obviously”,
“attachments”: []
},
{
“description”: “Step 2 – log in with happy path”,
“expected”: “user is redirected to the home screen”,
“attachments”: []
},
{
“description”: “Step 3 – click hamburger bar “,
“expected”: “side menu shows up”,
“attachments”: []
}]
14)最终请求标头使用第一次调用的令牌。如前所述,我们可以使用带有双括号表示法{{}}的已保存变量:
和请求身体:
- 然后进行一些测试:
要验证响应,请进入测试选项卡,确保返回正确的数据。
15)现在,您可以使用“Runner”立即运行整个测试套件或仅运行子文件夹。
这些通常都是快乐的路径,但是这些调用可能会出现很多问题,而且你可以做几十或几百个测试,包括很多安全测试。如果项目属于另一个客户怎么办?如果模块ID不存在怎么办?如果你上传一个庞大的文件怎么办?写一次,每次测试!
我们没有涉及的一个重要项目是存储不同的环境。如果要对开发,QA,登台或生产环境进行测试,则可能需要为每个环境使用不同的测试数据或登录。您可以设置它并在通过GUI运行测试时选择环境(如我们所见)或从Newman的命令行中选择。我们接下来就这样做。
Set Up Newman
既然您有一个要执行的集合,并且可能是相应的环境配置,那么您将需要从命令行运行它。您必须能够执行此操作才能从Jenkins或任何其他持续集成调度程序运行它。为此,我推荐Newman,它是一个可执行程序,用于运行Postman集合,这些集合是用Javascript编写的,可以与节点包管理器(NPM)一起安装。只需几个小步骤:
1)打开您选择的终端/命令行应用程序:https://www.davidbaumgold.com/tutorials/command-line/
2)安装npm:https://www.npmjs.com/get-npm
3)在您的机器上全局安装Newman:https://www.npmjs.com/package/newman/tutorial
4)从Postman导出您的收藏(只需右键单击要在左窗格中导出的测试)并从Postman导出您的环境(转到“管理环境”并点击下载按钮)。 将这些保存在您在终端中导航的计算机上。
5)一旦你进入你的终端,除了运行你的测试之外别无选择! 在这种情况下,您不需要任何选项或环境变量,因此命令应该只说:
`newman run path / to / my / exported / json / postman / collection.json`
看起来很漂亮吧?漂亮很棒,但是当你使用Jenkins时却不是!让我们使用Jenkins可以理解的更典型的JUnit输出。就像是:
`newman run -reporters junit,json path / to / my / exported / json / postman / collection.json
此命令实际上产生两种类型的输出:标准的,描述性较低的JUnit以及高度描述性的.json文件。看看两者 - 它们应该在你工作目录中名为“Newman”的文件夹下创建(也就是运行Newman命令的目录)。
我们很快就会编写一个脚本来将测试结果上传到qTest,并且使用JUnit输出将允许Jenkins显示内置图形并帮助系统在没有任何其他帮助的情况下通过或失败构建。
虽然您也可以使用JUnit结果和自动化内容将结果直接上传到qTest Manager,但使用API可以更灵活地确定测试结果在工具中的显示方式和位置。
现在我们已经从命令行运行了测试,现在是时候将它放入我们的Jenkins作业中,这样它就可以作为持续集成的一部分。我建议每次开发人员推送到工作分支时,都要针对您的开发环境运行此操作。
从Jenkins执行你的测试
我不会进入Jenkins的设置,只是作业的配置,但如果你想在本地试用,这里是下载页面。
如果您不想直接在计算机上安装Jenkins,可以使用Docker进行安装。如果您确实想使用Docker,可以先下载事实上的Jenkins Docker实例,然后使用Docker / Jenkins存储库中的以下节点安装代码将Dockerfile更改为包含节点:
#安装节点
运行curl -sL https://deb.nodesource.com/setup_4.x |庆典
运行apt-get -y安装nodejs
运行节点-v
运行npm -v
运行npm install -g newman
从这里开始,您需要重建Docker镜像,然后使用与此GitHub自述文件相同的说明启动容器。
您现在应该在本地安装一个完全正常工作的Jenkins实例。大!现在回到使用新安装的Jenkins实例的任务:
1)在Jenkins中创建一个新的“Freestyle”类型的工作。
在这种情况下,我们将其设置为允许您将集合作为参数上载。当您使用自己的项目执行此操作时,您应该将Postman集合提交到您正在使用的任何存储库中,并通过选择“此项目已参数化”然后选择“添加参数”并使用“文件参数”直接从该存储库中进行构建“。
2)选择两个文件上传 - 一个用于集合,一个用于环境。
3)使用“执行Shell”添加后构建步骤(如果Jenkins在Windows机器上运行,则执行“执行Windows批处理命令”)。 您将使用之前用于从您自己的命令行运行它的相同命令(假设您使用相同的操作系统),除了您的路径现在应该只是collection.js,因为您将其命名为`newman run collection.json` 在文件参数名称字段中。
4)现在测试它并运行构建。 我刚刚上传了collection.json,因为我还没有使用环境文件,但你可以将它添加到命令行:
`newman run collection.json -e environment.json`
为确保一切正常,请检查测试的内容 - 应该在项目中添加一些新的测试用例。
此外,如果要使用内置的JUnit Jenkins查看器,可以存档XML测试结果并将测试指向它。 以下是如何归档和使用JUnit测试结果的示例。 如果您正在使用qTest Manager,也可以在此处下载Jenkins qTest Manager插件。
通过API将结果上传到qTest
此时,我们已成功编写了与CI作业一起运行的测试。如果测试失败,我们可能会失败这里的构建(API测试的好主意!),但我认为我们还应该将测试结果上传到qTest,以证明这些测试通过或失败。为此,我们可以使用我编写的脚本,您可以在此处找到该脚本。
1)要使用此脚本,我们将使用纽曼的.json记者。
在该文件夹中,您应该找到您的样本Newman测试结果。如果您想在不在Postman中设置测试的情况下尝试此节点脚本,您可以,但是您需要修改.json测试结果文件以使数据与您自己的项目相匹配。在下面的示例中,您将需要更改测试用例ID以匹配您自己项目中的测试用例ID。
2)现在我们将使用该命令运行脚本
node uploadNewmanToQTest.js -f newman-json-result.json -c creds.json -i true -r“([0-9] +)\ - *?”
-r选项之后的部分有点可怕。它是一个JavaScript正则表达式,告诉脚本在哪里查找测试用例ID(如果存在-i false,则为名称)。这将获得第一个数字并将它们用作测试用例ID。默认情况下,如果未提供正则表达式,则将使用结果中的整个测试用例名称。例如,如果测试用例名称为“Verify Successful Login”和-i false(使用测试用例名称而不是ID),那么它将查找名为“Verify Successful Login”的相应测试用例。当然,如果此名称出现两次,它将更新两个测试用例的相关测试运行。此脚本有很多选项,并非所有选项都已完成。如果您有什么想看的,请不要犹豫,评论或删除QASymphony。
就是这样,因为你应该得到一个成功的输出!
当然,这只是众多API测试的一个例子。您还可以查看这篇Postman教程和Postman&Jenkins的介绍,了解更多精彩信息。
如果您有任何具体要求,请在下面评论,我会尽力回复。否则,快乐测试!
- 54 次浏览
【API测试】使用Dredd测试您的API
通常,在开发应用程序时,前端和后端开发人员在实现路径上采用两条不同的路径。前端开发人员更多地是设计驱动的,而后端开发人员则更注重数据。这通常会导致潜在的整合差距,其中一个团队在提供的数据,响应的结构等方面具有某些期望,而另一个团队实现完全不同的东西。
介绍
在本文中,我们将展示一个技术堆栈,旨在弥合前端和后端开发人员之间的差距,使我们能够记录API并在实现后不断测试它。
本文中介绍的堆栈包含以下内容:
- Dredd - 使用API Blueprint和Swagger API描述格式的API测试工具
- API Blueprint - 规范语言,允许我们以类似Markdown的语法记录我们的API
- Drakov - 可以使用我们API的API蓝图描述并设置模拟服务器来托管端点的工具
本文中的示例将使用简单的Node.js API和Express中间件显示。
安装和设置
Dredd基于Node.js,因此在安装之前,请确保在您的计算机上安装了Node.js和npm。 它可以使用以下命令安装为npm包:
> npm install -g dredd
安装完成后,您可以通过运行来检查它是否正确安装:
> dredd --version
API Blueprint描述文件的简单示例
假设我们有一个带端点的API来创建新用户:
POST /api/users
它接受包含电子邮件和密码值的JSON请求正文:
{ "email": "testing@email.com", "password": "pa55w0rd" }
用于测试以下端点的API Blueprint规范如下所示:
FORMAT: 1A # Dredd example ## Users [/api/users] ### Create User [POST] + Request (application/json) { "email": "test@email.com", "password": "pa55w0rd" } + Response 200 (application/json; charset=utf-8) + Headers jwt-token: (string, required) + Body { "id": 1, "email": "test@mail.com", "password": "pa55w0rd", "provider": "local", "role": "user" }
我们可以通过两种方式根据Blueprint文件验证API实现。
手动运行
Dredd使我们能够通过指定API蓝图文件的名称和API的URL来运行临时测试:
> dredd api-description.apib http://localhost:9090
上面的命令假设API Blueprint文件名为api-description.apib,并且您的API在端口9090上的本地计算机上运行。根据您的设置,值可能会有所不同。
配置运行
还有一种更简单的方法来设置Dredd,即运行> dredd init命令,该命令运行配置向导以帮助您在项目根目录中创建dredd.yml文件。 从交互式向导回答几个问题后,只需输入以下命令即可运行测试:> dredd。 如果配置正确,Dredd将使用您向向导提供的命令启动后端服务器进程并开始测试。
在这两种情况下,输出都与此类似:
> dredd info: Configuration './dredd.yml' found, ignoring other arguments. warn: Apiary API Key or API Project Subdomain were not provided. Configure Dredd to be able to save test reports alongside your Apiary API project: https://dredd.readthedocs.io/en/latest/how-to-guides/#using-apiary-reporter-and-apiary-tests info: Starting backend server process with command: npm run start info: Waiting 3 seconds for backend server process to start > dredd-example@0.0.1 start /Users/code/dredd-example > node server/app.js Express server listening on 9000, in development mode info: Beginning Dredd testing... pass: POST (200) /api/users duration: 55ms complete: 1 passing, 0 failing, 0 errors, 0 skipped, 1 total complete: Tests took 901ms POST /api/users 200 4.167 ms - 151 complete: See results in Apiary at: https://app.apiary.io/public/tests/run/f1642892-a4eb-4970-8423-5db5c986a509 info: Backend server process exited
由于我们没有指定任何API密钥,Dredd警告我们测试运行不会保存到我们的Apiary帐户。 在这种情况下,它们被保存为公共运行并保存24小时,这对于本文来说已经足够了。 让我们使用输出中的URL打开我们的测试运行(注意 - 您的URL会有所不同):https://app.apiary.io/public/tests/run/f1642892-a4eb-4970-8423-5db5c986a509
在Test Run Viewer中,我们可以检查测试运行中的每个请求,返回的响应,差异和结果。
使用挂钩进行设置和拆卸
与许多其他测试框架一样,Dredd还支持添加挂钩以运行设置和拆卸代码,编写自定义期望,处理授权以及在测试之间共享数据。 钩子可以用许多支持的语言编写,在本文中,我们将看到如何在本机支持的Node.js中添加钩子。
我们首先在项目中添加一个钩子文件(在我们的例子中,我们可以将它添加到项目根目录并命名为dredd-hooks.js)。
有两种方法可以让Dredd使用钩子文件。 一种是手动添加命令参数和我们的钩子文件的路径:
> dredd --hookfiles=dredd-hooks.js
另一种方法是编辑我们的dredd.yml文件并通过设置hookfiles属性来更新配置。
dry-run: null hookfiles: dredd-hooks.js language: nodejs sandbox: false server: npm run start server-wait: 3 init: false custom: {} names: false only: [] reporter: apiary output: [] header: [] sorted: false user: null inline-errors: false details: false method: [] color: true level: info timestamp: false silent: false path: [] hooks-worker-timeout: 5000 hooks-worker-connect-timeout: 1500 hooks-worker-connect-retry: 500 hooks-worker-after-connect-wait: 100 hooks-worker-term-timeout: 5000 hooks-worker-term-retry: 500 hooks-worker-handler-host: 127.0.0.1 hooks-worker-handler-port: 61321 config: ./dredd.yml blueprint: api-description.apib endpoint: 'http://localhost:9000'
现在我们有了文件,我们可以开始围绕每个事务编写代码。 Dredd在API蓝图描述文件(.apib)中按名称标识事务。 要在测试运行期间列出事务名称,可以添加--names命令参数:> dredd --names。
在我们的示例中,我们有一个名为Users> Create User的事务,我们将在代码中引用它。
当我们的API中有很多端点时,挂钩尤其重要,我们不希望依赖于它们执行的任何特定顺序。 例如,如果我们有一个删除用户的端点,为了单独测试它(不依赖于首先运行的Create User端点),我们必须在执行测试之前创建一个测试用户。 这是钩子文件的样子:
var hooks = require('hooks'); var User = require('../dredd-example/server/api/user/user.service'); var testStash = { newUserId: null }; hooks.before('Users > Delete User', function(transaction) { hooks.log('Executing hook "before" transaction "Users > Delete User"'); User.save({ email: 'user@test.com', password: '12345' }, function(err, newUser) { if (!err) { hooks.log('New user created'); testStash.newUserId = newUser.id; } else { transaction.fail = 'Unable to create new user'; } }) }); hooks.after('Users > Delete User', function(transaction) { hooks.log('Executing hook "after" transaction "Users > Delete User"'); // In case the actual test failed, we want to clean up the data if (testStash.newUserId != null) { User.delete(testStash.newUserId); } });
上面的代码中有几点需要考虑:
我们声明了一个名为testStash的新变量,我们用它来保存跨多个测试钩子的新创建用户的ID。
在before hook中,如果我们无法创建用户,我们可以通过使用失败消息设置fail属性来手动测试失败。
在挂钩后,我们从存储中获取用户的ID,并在测试后通过删除用户来清理它。
设置模拟服务器
使用API Blueprint格式记录的API时,另一个很酷的功能是我们也可以使用相同的文件来启动模拟服务器来托管我们的端点。这对前端开发人员特别有用,因为他们不必等待API完成和部署。相反,他们可以使用.apib文件来启动模拟服务器,将客户端应用程序与它集成,并确保真正的API也符合相同的规范。
该工作的工具称为Drakov,它也可以通过运行以下命令安装为npm包:
> npm install -g drakov
安装完成后,我们只需键入以下内容即可将Drakov指向我们的API Blueprint文件:
> drakov -f api-description.apib
此命令将使用默认参数运行Drakov并显示以下输出:
> drakov -f api-description.apib [INFO] No configuration files found [INFO] Loading configuration from CLI DRAKOV STARTED [LOG] Setup Route: GET / Get Message [LOG] Setup Route: POST /api/users Create User [LOG] Setup Route: GET /api/users/:id Get User Info [LOG] Setup Route: DELETE /api/users/:id Delete User Drakov 1.0.4 Listening on port 3000
现在,我们可以对模拟的API执行任何HTTP操作,并开始获取文档中定义的HTTP响应。
最后的话
今天提供的工具既简单又直接,但也非常强大。 它们涵盖了许多任务,包括记录API,测试实现以及运行模拟服务器以方便使用。
Dredd有很多选项,可以配置各种类型的请求。 它还可以与所有主要的CI工具集成,以便重复测试,为开发人员提供了一个很好的安全网。
API Blueprint是一种非常富有表现力的降价格式,可用于描述请求和响应的几乎所有细节。
Drakov非常简单,可以通过运行一个简单的命令来开箱即用。
所有这些只需要几个小时来准备和配置,之后您将能够告别未记录的API。
- 117 次浏览
【合约测试】Pact 101 - 契约和消费者驱动的合同测试入门
所以你听说过Pact并希望开始。本指南应该有助于您朝着正确的方向前进。
什么是Pact?
Pact系列测试框架(Pact-JVM,Pact Ruby,Pact .NET,Pact Go,Pact.js,Pact Swift等)为依赖系统之间的消费者驱动合同测试提供支持,其中集成基于HTTP(或消息)某些实现的队列)。它们对于μ服务特别有用,在这些服务中可能存在大量相互依赖的服务,并且集成测试很快变得不可行。
在我们深入了解Pact之前,您需要了解消费者驱动的合同。
什么是消费者驱动的合同?
消费者驱动的合同是一种模式或方法,其中相互依赖的服务之间的合同是从服务消费者的角度设计的。它的主要文章是消费者驱动的合同:服务进化模式,但它在技术方面有点过时(它谈论了很多关于XML和模式)。但是文章中表达的概念与我们今天构建的计算机系统有关。
我发现很多时候构建μ服务或内部API的团队都遵循与外部或公共API相同的思路。服务提供商或API团队会考虑其服务的任何消费者需要的所有内容(在此过程中做出许多假设),然后提供服务以及如何使用它的文档。他们建立它并希望消费者来。
当他们稍后需要更改它时,他们会进行更改,然后将其与所有消费者需要遵循的说明一起发布以使用更新的API。它们可能包含多个版本的服务,以保护消费者免受重大变化的影响。
我目睹了第一手开发和使用API的两个团队。 在构建消费者和提供者之后,他们花了很多天才在集成测试环境中进行交互,因为消费者团队认为API将基于发布JSON文档(它是从Web浏览器调用),而 提供程序团队实现了application / x-www-form-urlencoded POST API。
但具有讽刺意味的是,对于内部API和服务而言,要弄清楚服务的所有消费者是谁以及他们的要求是什么并不难。 大多数时候,他们都在同一个组织工作。
消费者驱动的合同扭转了这一切。 交互合同由服务的消费者开发。
这种方法的好处是,您知道您的服务的所有消费者是谁,您将知道何时进行重大更改,以便更容易进行更改,合同也是一种文档形式。 其次,您将确切地知道需要提供哪些功能,以便您可以实现消费者所需的正确服务,并遵循YAGNI原则。
交互的发展始于消费者方面,希望通过测试。 消费者团队定义交互合同并根据合同实现服务使用者。
然后将此合同提供给提供者团队(在某些情况下,它是同一个团队),并且实施提供者服务以履行合同。
开始时我需要做什么?
大多数信息可以在Github页面上找到,用于各种Pact实现。 Ruby Pact在wiki中有很多信息。
- Ruby Pact: https://github.com/realestate-com-au/pact
- JVM Pact: https://github.com/DiUS/pact-jvm
- .Net Pact: https://github.com/SEEK-Jobs/pact-net
- Pact Go: https://github.com/pact-foundation/pact-go
- Pact.js: https://github.com/pact-foundation/pact-js
- Pact Swift: https://github.com/DiUS/pact-consumer-swift
- Pact Python: https://github.com/pact-foundation/pact-python
特别是,要了解Pact的工作原理,请阅读:https://github.com/realestate-com-au/pact#how-does-it-work。
从消费者测试开始
这完全是关于消费者的,所以从那里开始。支持许多测试框架,因此根据您使用的测试工具,请阅读相关文档。
对于Ruby和RSpec,请阅读使用pacts简化微服务测试的示例。
对于基于JVM的测试框架(JUnit,Groovy等),请查看https://github.com/DiUS/pact-jvm#service-consumers。 JUnit似乎是最受欢迎的。有很多示例测试。
一旦运行了消费者测试,就应该生成pact文件。这些是消费者驱动合同意义上的合同。您可以通过多种方式发布这些文件。常见的方法是将它们提交到源存储库,将它们上载到文件服务器,将它们存储为CI构建中的工件或将它们上载到Pact Broker。
验证您的提供者
该方法的后半部分是验证您的提供商实际上是否符合消费者的期望。对于已实现消费者测试的每个消费者,您应该在某处发布pact文件。通常,您希望在其CI构建中验证您的提供商,以便您知道更改何时破坏了与消费者的交互,并且您还将知道您受影响的消费者。
给定一组已发布的pact文件,有两种主要方法可以验证您的提供程序是否遵守pact文件中封装的合同。
使用构建插件来验证协议
第一种方法是使用构建插件,该插件可以在pact文件中针对您的提供者执行请求。在某些情况下(如Ruby Rake任务),提供程序从测试工具(Rack Test for ruby)中启动,重放请求,然后将响应与pact文件的预期响应进行比较。在其他情况下(如Maven和Gradle插件),实际的提供程序需要运行,构建插件会向正在运行的提供程序发出实际请求。
有关为Ruby提供程序使用Ruby Rake任务的示例,请阅读使用pacts简化微服务测试的“提供程序”部分。
JVM构建插件(Maven,Gradle,Leiningen和SBT)的自述文件包含有关如何使用这些工具的更多信息。在大多数情况下,您需要能够事先启动您的提供程序并在之后停止它,并且有办法提供协议所需的测试数据。有关更多信息,请参阅Pact-JVM自述文件的“服务提供程序”部分。
Pact具有状态更改机制,用于在验证测试运行期间控制提供程序的状态。本质上,这是一个可以在每个请求之前调用的钩子,其中描述了提供者为了能够成功处理请求而需要的预期状态。例如“用户Andy应该存在”或“订单表应该为空”。 Ruby实现允许定义设置和拆除块,而JVM构建插件允许定义状态更改URL,该URL将在实际请求发出之前接收具有状态描述的POST请求。
使用测试框架来验证契约
使用某些构建插件的最大缺点是,您需要让您的提供程序运行,并且您需要能够设置测试数据。这涉及预先加载所有契约所需的夹具数据,或者使用状态更改机制来动态更改提供者的状态。这两种方法都需要相当多的编排,尤其是在CI环境中。
由于社区贡献,Pact JUnit提供程序运行程序可供使用基于JVM的提供程序的人员使用。它允许您仅处理提供者处理请求的部分提供者代码,并且您可以使用JUnit设置和拆除机制以及状态注释标记来设置协议所需的数据。您也可以使用标准的模拟框架来存根依赖关系,尽管我会添加一个警告,以确保您不会影响您的模拟和存根的行为。自述文件包含更多信息。
原文:https://dius.com.au/2016/02/03/microservices-pact/
讨论:加入知识星球【首席架构师圈】
- 145 次浏览
【合约测试】Pact Broker是一个用于共享消费者驱动的合同和验证结果的应用程序。
启用您的消费者驱动的合同工作流程http://pactflow.io
Pact Broker是一个用于共享消费者驱动的合同和验证结果的应用程序。它被优化用于“pacts”(由Pact框架创建的契约),但可以用于任何类型的可以序列化为JSON的契约。
我为什么需要一个?
合同测试是传统集成测试的另一种方法,它为您提供更快速执行的测试,并且可以更大规模地维护。该方法的一个缺点是在集成测试套件执行结束时可以在一个地方获得的重要信息(即,一起测试的所有应用程序的版本号,以及测试是否通过或失败的)现在分散在许多不同的版本中。 Pact Broker是一个工具,可以将所有这些信息重新组合在一起,并允许您安全地部署。
它:
- 通过独立部署服务并避免集成测试的瓶颈,您可以快速,自信地发布客户价值
- 解决了如何在消费者和提供者项目之间共享合同和验证结果的问题
- 告诉您可以安全地一起部署哪些版本的应用程序
- 自动修改合同
- 允许您确保多个消费者和提供者版本之间的向后兼容性(例如,在移动或多租户环境中)
- 提供您的应用程序的API文档,保证是最新的
- 向您展示服务如何交互的真实示例
- 允许您可视化服务之间的关系
特征:
- 用于发布和检索协议的RESTful API。
- 用于导航API的嵌入式API浏览器。
- 每个协议的自动生成文档。
- 动态生成的网络图,以便您可以可视化您的微服务网络。
- 显示提供程序验证结果,以便您知道是否可以安全部署。
- 提供兼容的消费者和提供商版本的“矩阵”,以便您了解哪些版本可以安全地一起部署。
- 提供徽章以在README中显示协议验证状态。
- 允许标记应用程序版本(即“prod”,“feat / customer-preferences”)以允许类似于存储库的工作流程。
- 提供webhook以在pacts更改时触发操作,例如。运行提供程序构建,通知Slack通道。
- 查看Pact版本之间的差异,以便了解哪些期望已发生变化。
- Docker Pact Broker
- 用于将Pact工作流程加载到持续集成过程的CLI。
我如何使用Pact Broker?
步骤1.消费者CI构建
- 使用者项目使用Pact库运行其测试以提供模拟服务。
- 测试运行时,模拟服务将请求和预期响应写入JSON“pact”文件 - 这是消费者合同。
- 然后将生成的协议发布到Pact Broker。大多数Pact库都会为您提供一个可以轻松完成此任务的任务,但是,最简单的是,它是指定消费者名称和应用程序版本以及提供者名称的资源的PUT。例如:http://my-pact-broker/pacts/provider/Animal%20Service/consumer/Zoo%20App/version/1.0.0(请注意,您在URL中指定了消费者应用程序版本,而不是协议版本。当内容发生变化时,代理将负责在幕后对该协议进行版本控制。预计消费者应用程序版本将随着每个CI构建而增加。)
- 发布协议时,如果协议内容自上一版本以来发生更改,则Pact Broker中的webhook将启动提供程序项目的构建。
步骤2.提供者CI构建
- 提供程序具有验证任务,该任务使用URL进行配置,以检索自身与使用者之间的最新协议。例如http:// my-pact-broker / pacts / provider / Animal%20Service / consumer / Zoo%20App / latest。
- 提供者构建运行pact验证任务,该任务从Pact Broker检索pact,对提供者重放每个请求,并检查响应是否与预期响应匹配。
- 如果协议验证失败,则构建失败。 Pact Broker CI Nerf Gun神奇地确定是谁导致验证失败,然后射击它们。
- 验证结果由契约验证工具发布回Pact Broker,因此消费者团队将知道他们编写的代码是否可以在现实生活中使用。
如果您没有Pact Broker CI Nerf Gun,那么当消费者和提供者由不同的团队编写时,您可能想要阅读有关使用pact的信息。
步骤3.返回Consumer CI构建
以下功能是测试版。您的反馈意见将不胜感激。
- 消费者CI通过运行pact-broker can-i-deploy --pacticipant CONSUMER_NAME --version CONSUMER_VERSION ...来确定协议是否已经过验证(请参阅此处的文档)
- 如果已验证协议,则可以继续部署。
在Wiki页面的概述中阅读有关如何使用Pact Broker的更多信息。
文档
有关Pact Broker的文档,请参阅Wiki。请首先阅读概述页面,以了解代理中的HTTP资源以及它们之间的相互关系。
截图
Index
自动生成的文档
将pact URL粘贴到浏览器中以查看该协议的HTML版本。
Network diagram
HAL浏览器
使用嵌入式HAL浏览器导航API。
HAL文档
在浏览时使用HAL浏览器查看文档。
用法
在本地计算机上玩游戏
- Install ruby 2.2.0 or later and bundler >= 1.12.0
- Windows users: get a Rails/Ruby installer from RailsInstaller and run it
- unix users just use your package manager
- Run
git clone git@github.com:pact-foundation/pact_broker.git && cd pact_broker/example
- Run
bundle install
- Run
bundle exec rackup -p 8080
(this will use a Sqlite database. If you want to try it out with a Postgres database, see the README in the example directory.) - Open http://localhost:8080 and you should see a list containing the pact between the Zoo App and the Animal Service.
- Click on the arrow to see the generated HTML documentation.
- Click on either service to see an autogenerated network diagram.
- Click on the HAL Browser link to have a poke around the API.
- Click on the book icon under "docs" to view documentation related to a given relation.
真的
Hosted
In a hurry? Hate having to run your own infrastructure? Check out the Hosted Pact Broker - it's fast, it's secure and it's free!
Container solutions
You can use the Pact Broker Docker image or Terraform on AWS. See the wiki for instructions on using a reverse proxy with SSL.
Rolling your own
- Are you sure you don't just want to use the Pact Broker Docker image? No Docker at your company yet? Ah well, keep reading.
- Create a PostgreSQL (recommended) or MySQL (not as recommended because of @bethesque's personal prejudices, but still fully supported) database.
- To ensure you're on a supported version of the database that you choose, check the travis.yml file to see which versions we're currently running our tests against.
- If you're using PostgreSQL (did we mention this was recommended!) you'll find the database creation script in the example/config.ru.
- Install ruby 2.4 or later and the latest version of bundler (if you've come this far, I'm assuming you know how to do both of these. Did I mention there was a Docker image?)
- Copy the pact_broker directory from the Pact Broker Docker project. This will have the recommended settings for database connections, logging, basic auth etc. Note that the Docker image uses Phusion Passenger as the web application server in front of the Pact Broker Ruby application, which is the recommended set up.
- Modify the config.ru and Gemfile as desired (eg. choose database driver gem, set your database credentials. Use the "pg" gem if using Postgres and the "mysql2" gem if using MySQL)
- example Sequel configuration for postgres
{adapter: "postgres", database: "pact_broker", username: 'pact_broker', password: 'pact_broker', :encoding => 'utf8'}
- example Sequel configuration for mysql
{adapter: "mysql2", database: "pact_broker", username: 'pact_broker', password: 'pact_broker', :encoding => 'utf8'}
`
- example Sequel configuration for postgres
- Please ensure you use
encoding: 'utf8'
in your Sequel options to avoid encoding issues. - For production usage, use a web application server like Phusion Passenger or Nginx to serve the Pact Broker application. You'll need to read up on the documentation for these yourself as it is beyond the scope of this documentation. See the wiki for instructions on using a reverse proxy with SSL.
- Ensure the environment variable
RACK_ENV
is set toproduction
. - Deploy to your location of choice.
升级
Please read the UPGRADING.md documentation before upgrading your Pact Broker, for information on the supported upgrade paths.
原文 :https://github.com/pact-foundation/pact_broker
讨论: 知识星球【数字化和智能转型】
- 221 次浏览
【合约测试】使用Postman进行消费者驱动的合同测试
实施消费者驱动的合同测试是维护不断增长的微服务堆栈的好方法。 它使团队在定期完成时不会因API差异而受阻。 这是Postman如何帮助您做得更好。
API行为通常在文档页面中描述,该页面列出了可用的端点,请求数据结构和预期的响应数据结构,以及示例查询和响应。然后,构建使用这些API的系统的人员将使用这些文档。
但是,单独编写的文档不会保护API的使用者免受API的更改。 API生产者可能需要更改响应数据结构或完全重命名端点以满足业务需求。
然后,合并这些更改的责任落在那些必须不断检查文档以进行任何更改的API的消费者身上。该模型不能很好地扩展。消费者经常会遇到意想不到的错误,因为他们期待的反应已经发生了变化。
这是让消费者对API合同断言变得有用的地方。这些API的消费者可以通过让生产者知道他们想要从API获得哪些数据来设置期望,而不是让API生成者自己构建规范。
然后,API设计将转变为消费者需要的内容与提供商可以提供的内容之间的协商。
使API合约显式且可执行
Postman在今年早些时候进行了一项调查,结果显示大多数业务API都是内部的。这些是在组织内构建服务的团队,这些团队聚集在一起构建面向用户的更大产品。在这种情况下,确保消费者的期望与API提供的数据之间没有差异,这成为组织工作流程的重要组成部分。拥有明确,可共享和可执行的合同可以防止这种混乱和挫折。
生产者可以通过使用市场上任何流行的工具(如RAML,API Blueprint,OpenAPI,Pact或Postman Collections)为其API创建规范,而不是在静态页面中记录API行为。最后两个,Pact和Postman让您实现消费者驱动的合同作为一流的概念。 Pact进一步专注于合同测试,而Postman生态系统除此之外还包含更多功能。
所有这些格式都允许您指定有关API行为的详细信息。它们允许您通过端点名称,描述,数据类型以及请求和响应的数据结构来传达API的意图。他们还支持向每个端点添加示例。
一旦获得这些格式的规范,就可以运行生成测试代码的工具,或使用规范中描述的端点结构直接将请求发送到给定服务。您获得的灵活程度因您使用的工具集而异。
这些规范构成了服务合同的来源 - 生产者提供的内容与消费者期望的内容之间的协议。每个工具集的基本价值在于,它们使您的API结构对于协作构建服务以及服务的使用者而言是明确的。
针对多个消费者测试合同
如果您是消费者,拥有这样的规范便可让您确切地知道要从API中获取哪些数据。您可以编写测试来设置期望并断言您的服务将使用的数据。这种方法有两个主要好处:
- 只要规范发生变化,您就可以运行测试套件,并主动响应API规范中的更改,并且,
- 您可以作为消费者参与API的设计过程,并在合同正式化之前让您的需求得到了解。
在消费者驱动的合同测试中,合同由消费者明确编写和管理。如果生产者需要对其服务进行一些更改,例如实施新功能,生产者只需查看哪些消费者的合同测试失败就可以了解他们打破了哪些消费者。这使得API提供商不必担心每次他们对服务进行一些更改时都会意外破坏消费者应用或服务。
独立服务测试
这减少了执行端到端服务测试的需要。如果所有合同测试都通过,API生产商可以合理地确定他们的服务在与其他服务集成时按预期执行。对于在微服务环境中进行端到端测试的复杂性而言,这是一个巨大的缓解。
对于API的每次更改,端到端测试都是昂贵且繁琐的。生产者和消费者可以按照自己的步调移动,拥有自己的路线图并不断部署他们的变化。消费者团队只有在合同测试失败时才需要担心。将此与从规范自动生成的更新文档相结合,可以快速检测故障,而无需构建运行端到端测试所需的复杂设置。
将Postman用于消费者驱动的合同
Postman拥有您开始在组织中实施合同测试所需的所有工具。 Postman Collections是API的可执行规范。您可以使用Postman应用程序在本地计算机上运行集合,在命令行上使用newman运行CI系统,使用监视器在云中运行集合。在任何一种情况下,集合中的请求都是按顺序执行的。
此外,您可以使用预请求脚本为请求添加动态行为,并通过测试对响应进行断言。有关在Postman中从手动过渡到自动API测试的文章将向您介绍这些步骤的详细信息。
将所有这些与Postman中的Workspace相结合,您就可以为整个团队准备好可执行,共享和协作的合同集合。您无需与团队成员手动共享这些详细信息。
让我向您介绍一个示例用例,了解这些用例如何实现以消费者为导向的合同。
示例用例:简单日志检索服务
假设我们需要构建一个假设的服务,该服务返回来自某个集中式日志存储的日志条目列表。此服务仅公开一个端点(为简单起见),它返回最新的5个日志条目,其中包含创建条目的服务的名称,条目的时间戳以及描述该条目的描述字符串。
端点位于/ api / v1 / logs。向此端点发送GET请求应该返回此结构中的JSON数据:
{ "count": Number, "entries": Array[Object] }
entries数组将包含每个日志条目的对象。他们的数据结构如下所示:
{ "serviceName": String, "timestamp": Number, "description": String }
蓝图
首先,我们创建一个蓝图集合。蓝图集合规定了API结构。这是由服务的生产者创建的。
您可以在此处访问此示例的蓝图集合。
示例蓝图集合
然后,我们为请求添加示例。我已经添加了一个例子。示例允许此类蓝图集合描述响应数据。它们出现在Postman生成的文档中。以下是此服务的默认输出的响应数据示例:
{ "count": 5, "entries": [ { "serviceName": "foo", "timestamp": 1540206226229, "description": "Received foo request from user 100" }, { "serviceName": "bar", "timestamp": 1540206226121, "description": "Sent email to user 99" }, { "serviceName": "foo", "timestamp": 154020622502, "description": "Received foo request from user 10" }, { "serviceName": "baz", "timestamp": 1540206223230, "description": "Activated user 101" }, { "serviceName": "bar", "timestamp": 1540206222126, "description": "Error sending email to user 10" } ] }
每个示例都有一个名称和特定的请求路径。这就是它在Postman应用程序中的外观:
添加示例以示例蓝图集合的请求
有了这些,Postman会自动为蓝图生成基于Web的文档。以下是已发布文档的截图。
由Postman从示例蓝图集合生成的已发布文档
作为创建此集合的工作空间的所有成员可以查看文档并访问集合,使其成为与其他成员协作的绝佳方式。然后,服务所有者可以基于此集合在Postman中创建模拟服务器。请求中添加的示例将作为模拟服务器响应的一部分发送。
在Postman中创建模拟服务器后,您可以在Postman为您生成的模拟服务器URL之后使用相同的端点向模拟服务发出请求。因此,向https:// <mock-server-id> .pstmn.io / api / v1 / logs发出请求将返回以下响应:
从样本集合创建的模拟服务器返回响应
写合同集合
服务的消费者可以根据蓝图和模拟来构建合同集合。 Postman测试允许您在响应的每个方面断言 - 包括响应标头,正文和响应时间。 因此,合同可以利用所有这些并构建可靠的测试。
对于此示例,我们假设此服务只有一个使用者。 为了简单起见,我们的契约集合示例也将有一个请求,它将仅在响应数据结构上断言。 现实世界的合同将断言数据结构以及响应中收到的数据。
以下是合同集合可用于测试上述数据结构的测试脚本。 它使用tv4库,它作为Postman Sandbox的一部分提供:
// Define the schema expected in response var responseSchema = { "type": "object", "properties": { "count": { "type": "number" }, "entries": { "type": "array", "items": { "type": "object", "properties": { "serverName": { "type": "string" }, "timestamp": { "type": "number" }, "description": { "type": "string" } } } } } }// Get response data as JSON var jsonData = pm.response.json();// Test for response data structure pm.test('Ensure expected response structure', function () { var validation = tv4.validate(jsonData, responseSchema); pm.expect(validation).to.be.true; });
合同集合在此发布。您可以使用该页面上的“Run in Postman”按钮在Postman应用程序中加载该集合,并浏览与该请求相关的测试。
请注意在合同集合中使用{{url}}变量占位符。当服务处于早期阶段时,消费者可以使用模拟服务器URL来发出请求。构建服务后,可以将环境变量切换为指向服务的托管实例。这样,消费者应用程序或服务的开发可以并行发生,而不会被阻止以构建上游服务。
持续测试
合同需要不断测试,以确保它们随着时间的推移有效。有两种方法可以实现。
如果您有一个现有的持续集成系统:您可以从Postman导出集合文件和环境,并使用newman从命令行运行它们。有关为Jenkins和Travis CI设置连续构建的步骤,请参阅newman的文档。每当规范或新版本的上游服务发生更改时,都可以触发构建管道。
除此之外,您还可以使用Postman Monitors运行合同集合。监视器可以定期运行,使其成为一个很好的工具,可以长期了解合同中断情况。
阅读有关使用Postman持续测试API的更多信息。
组织合同测试
真实世界的测试有设置和拆卸阶段。合同测试也不例外。合同测试的一个常见用例是使用某些数据填充正在测试的系统,然后对其执行操作,最后删除这些测试数据。
在Postman中模拟这种模式的一种巧妙模式是将Setup文件夹作为集合中的第一个文件夹,将Teardown文件夹作为集合的最后一个文件夹。然后,所有合同测试都将作为Setup和Teardown文件夹之间的文件夹。这将确保Postman始终在集合运行开始时在Setup文件夹中运行请求,然后运行执行实际测试的请求,并以运行Teardown文件夹中的所有请求结束。
在编写内部合同时,我们会大量使用这种模式。
这有助于通过抽象出第一个和最后一个文件夹中的重复任务来巧妙地分组和组织测试。 理想情况下,API生产者应提供包含Setup和Teardown请求的集合。 消费者可以创建该集合的副本并添加他们的合同测试。
合同测试的复杂性取决于您的业务案例。 编写消费者驱动的合同测试的一个额外好处是,通过查看服务所拥有的消费者合同集合的数量,您可以轻松发现服务变得太大或具有太多依赖性。
总体而言,消费者驱动的合同有助于保持表面区域以测试微服务并将变更协商到可控大小。
快乐的测试!
参考
- Consumer-Driven Contracts: A Service Evolution Pattern by Ian Robinson
- Building Microservices: Designing fine-grained systems by Sam Newman
- Microservices From Day One by Cloves Carneiro Jr., Tim Schmelmer
- How to be Confident That Your Microservices Can Still Communicate in Production with Pact and Docker by Harry Winser
原文:https://medium.com/better-practices/consumer-driven-contract-testing-using-postman-f3580dba5370
讨论: 加入知识星球【首席架构师圈】
- 124 次浏览
【微服务测试】合同测试与功能测试
合同测试和功能测试之间的差异似乎是一个经常出现在那些开始认真投资于合同测试的团队的辩论。挑战在于它不是黑白相间的情况,而是更多的东西开始在合同测试的深度上爬行。
它可以是常见的一个地方是验证规则和被拒绝的请求。例如,我们可能有一个简单的用户服务,允许消费者注册新用户,通常使用POST请求,其中包含正文中创建的用户的详细信息。
这种交互的简单快乐路径场景可能如下所示:
Given "there is no user called Mary"
When "creating a user with username Mary"
POST /users { "username": "mary", email: "...", ... }
Then
Expected Response is 200 OK
坚持幸福路径存在丢失不同响应代码的风险,并且可能让消费者误解提供者的行为方式。那么,让我们来看一个失败的场景:
Given "there is already a user called Mary"
When "creating a user with username Mary"
POST /users { "username": "mary", email: "...", ... }
Then
Expected Response is 409 Conflict
到目前为止,我们正在使用不同的响应代码覆盖新行为。
现在我们一直在与管理用户服务的团队交谈,他们告诉我们用户名的最大长度为20个字符,他们只允许用户名中的字母和空白用户名显然无效。也许这是我们应该在合同中添加的内容?
这就是我们进入滑坡的地方......现在为我们的合同添加3个场景非常诱人,例如:
When "creating a user with a blank username"
POST /users { "username": "", email: "...", ... }
Then
Expected Response is 400 Bad Request
Expected Response body is { "error": "username cannot be blank" }
When "creating a user with a username with 21 characters"
POST /users { "username": "thisisalooongusername", email: "...", ... }
Then
Expected Response is 400 Bad Request
Expected Response body is { "error": "username cannot be more than 20 characters" }
When "creating a user with a username containing numbers"
POST /users { "username": "us3rn4me", email: "...", ... }
Then
Expected Response is 400 Bad Request
Expected Response body is { "error": "username can only contain letters" }
我们已经过了合同测试,我们实际上正在测试用户服务是否正确地实现了验证规则:这是功能测试,它应该由用户服务在其自己的代码库中涵盖。
这有什么害处...更多的测试是好的,对吧?这里的问题是这些场景太过分了,并且创建了一个不必要的紧密合同 - 如果用户服务团队确定实际上20个字符对用户名的限制太多并且将其增加到50个字符会怎么样?如果用户名中允许现在的号码怎么办?任何消费者都不应受任何这些变化的影响,遗憾的是,用户服务只会通过放松验证规则来破坏我们的契约。这些不是重大变化,但通过过度指定我们的方案,我们正在阻止用户服务团队实施它们。
让我们回到我们的场景,而只选择一个简单的例子来测试用户服务对错误输入的反应方式:
When "creating a user with an invalid username"
POST /users { "username": "bad_username_that_breaks_some_rule_that_you_are_fairly_confident_will_not_change", ... }
Then
Response is 400 Bad Request
Response body is { "error": "<any string>" }
微妙,但更灵活!现在,用户服务团队可以更改(大多数)他们的验证规则而不破坏我们给他们的契约...我们并不真正关心每个单独的业务规则,我们只关心如果我们发错了,那么我们理解用户服务响应我们的方式。
在为交互编写测试时,请问自己要覆盖的内容。合同应该是关于捕捉:
- 消费者中的错误
- 消费者对终点或有效负载的误解
- 中断提供者对端点或有效负载的更改
简而言之,您的Pact场景不应该深入了解提供商的业务逻辑,而应该坚持验证消费者和提供商是否对请求和响应有共同的理解。在我们的验证示例中,编写有关验证失败的方案,而不是验证失败的原因。
- 23 次浏览
【微服务测试】微服务测试策略
过去 10 年是分布式架构快速普及的时期。这种新架构背后的承诺是提高企业的敏捷性。频繁发布新功能使我们能够测试有关客户需求的假设。成功的关键因素之一是每次部署的信心。每次新软件版本即将投入生产时,运行一组测试所获得的信心。与测试范围由整个系统的复杂性定义的单体系统相比,在微服务中可以限制测试范围以节省时间,但仍不影响信心。这种新的架构方法需要审查我们所知道的测试结构。今天,我们将介绍对微服务系统的体面质量保证有用的自动化测试类型。
在本文中,您将学习
- 在微服务系统中测试什么
- 每个微服务部分需要哪些测试类型
- 如何有效地实施它们
- 如何平衡您的测试以实现成本和时间效率
本文中的所有代码示例都是用 Java 编写的,但所介绍的方法和模式也适用于其他语言。所有提到的工具都可以与不同的语言和框架一起使用,例如卡夫卡,WireMock。
微服务系统中的测试类型
当您查看典型应用程序的成分时,识别测试微服务所需的测试类型会更容易。通常它是一个被集成和协调代码包围的到达域。然后,系统的每个部分都由具有单一职责的较小单元组成,如果可能的话。
让我们尝试根据主题的标准来识别测试类型,测试应该检查。
单元测试
最小的软件片段通过单元测试进行测试。此类测试的目标是检查每个软件单元在与其他单元隔离的情况下是否正确运行。大多数专业开发人员每天都会编写它。测试的单元隔离是通过模拟所有依赖项来构建的。
单元测试的特点是:
- 速度——单个测试的平均执行时间低于 1 毫秒
- 可重复性——单元测试不依赖于环境
- 简单性——在狭窄的代码段上调用测试,因此很容易识别失败原因
集成测试
查看上图,您可以注意到微服务应用程序需要连接和协作的外部系统:
- 数据库,例如PostgreSQL
- 消息代理,例如阿帕奇卡夫卡
- 其他可通过 REST 或 SOAP 访问的服务
通常,在代码级别,开发人员会提取负责与外部系统通信的专用代码片段,并为域层和集成系统之间的通信提供方便的接口。
- 对于数据库集成,我们可以使用 ORM 和 Spring Data
- 对于消息代理集成,我们可以使用 Spring Cloud Streams 来创建消息网关
- 对于不提供 SDK 的 REST 服务,我们可以使用纯 Java 11 HTTP 客户端
集成测试的主题是那些提供与外部系统通信的类/功能。任何集成代码的单元测试几乎没有什么好处,因为它假定所有依赖项都被模拟。在集成测试中,即使使用集成系统的测试实例,也应该使用真实的网络协议访问所有依赖项。
与单元测试相比,集成测试需要更多的时间来执行并且不验证业务逻辑的实现。
相反,集成测试的目的是检查:
- 是否建立了与数据库的连接并且请求的查询是否正确执行
- 消息网关是否广播包含正确数据的消息
- HTTP 客户端是否正确理解服务器的响应
组件测试
让所有部分独立正常工作并确保所有外部依赖项都可以访问并不能保证整个微服务的行为符合预期。为了验证它,测试包含在单个组件中的完整用例或流程。外部依赖可以用进程内模拟来代替,以加快执行速度。每个测试都以通过公开接口的业务功能请求开始,并使用公共接口或通过检查模拟模式使用情况来验证预期结果。
除了检查微服务本身是否正常工作之外,组件测试还验证:
- 微服务配置
- 微服务是否与其依赖项/协作者正确通信
端到端测试
层次结构类型中最高的测试是 E2E 测试。在这种测试中,整个微服务系统都在运行,通常与生产环境的设置完全相同。成功的端到端测试结果意味着用户的旅程已经完成。端到端测试是最通用的测试类型,但这种通用性的代价是复杂性和脆弱性。
组件测试的目的是检查:
- 整个微服务系统是否正常工作
- 系统配置是否有效
- 微服务之间是否正确通信
- 整个业务流程能否顺利完成
测试类型分布
一旦我们确定使用不同类型的测试来确保代码在不同级别上“工作”,就该开始考虑实际问题了。
经验表明,与单元测试和集成测试相比,编写和维护组件测试的难度要高得多。
经验还表明,与组件测试相比,编写和维护 E2E 测试的难度要高得多。
知道了这一点,我们必须采取一些方法来跨测试类型分布我们的测试覆盖率。一般原则可以表述为“尝试用你能写的最简单的测试来测试实现的行为”。尽可能在单元测试级别测试您的功能。这些很便宜,因此您可以负担得起测试所有可能的情况。
如前所述,组件测试更难编写和维护,因此您希望将它们的数量保持在相当低的水平。与其测试每一个可能的案例,不如尝试限制自己从业务角度测试主要案例——例如一条“幸福的道路”和一条“悲伤的道路”。
另一方面,E2E 测试是完全不同的野兽。 E2E 测试失败的原因有很多,而且很难识别。请记住,组件和集成测试都不会捕获由以下原因引起的错误:
- 发生 HTTP 超时
- 系统配置错误
- 使用不兼容版本的合作服务
这意味着为了可维护性,E2E 测试应仅限于关键的业务流程和用户旅程。
测试系统概述
在本文的下一段中,我们将介绍已识别测试类型的实现。 为此,让我们回顾一下测试系统的高级快照。
出于本文的目的,让我们考虑一个系统“Piko”,它使用户能够管理和发布他们的旅游景点。
Piko 系统由三个部分组成:
piko-admin –> piko-locations <– piko-maps
从创建位置到发布的用户旅程包括以下步骤:
# | Description | Component |
1 | The user creates the location | piko-locations |
2 | The user marks the location as awaiting the publication | piko-locations |
3 | The administrator accepts the location | piko-admin |
4 | The published location is sent to the application that serves public traffic | piko-maps |
应用程序之间的大部分通信由 Kafka 消息代理处理。
对于用户身份验证,Piko 使用 AWS Cognito 服务颁发的 JWT 令牌。
您可以使用以下命令签出代码:
git 克隆 https://github.com/bluesoftcom/piko.git
实施单元测试
很可能,您已经在编写单元测试了。 该主题非常受欢迎,并且已经在大量其他材料中涵盖。 然而,让我们快速浏览一下可以使您的单元测试变得更好的一组实践。
让我们考虑以下测试用例:
@Test void testChangeLocationStatusToAwaitingForPublication() {
// given:
final LoggedUser loggedUser = someLoggedUser().build(); final Location location = someLocation().build(); when(locationsRepository.find(any())).thenReturn(location);
// when:
final DetailedJsonLocation updatedLocation = locationsService.updateLocationStatus( location.getId(), LocationStatus.AWAITING_PUBLICATION, loggedUser );
// then:
assertThat(updatedLocation.getStatus()).isEqualTo(LocationStatus.AWAITING_PUBLICATION); verify(locationsGateway).sendPublicationRequestIssued(location.getId()); }
这个单一的测试已经包含许多技巧/方法,确实使该测试清晰且可维护。
使用 given-when-then 结构保持您的测试井井有条
每个测试应包括三个部分:
- given——这代表了测试前关于世界状态的所有假设
- when - 这指定了测试的行为
- then——这描述了期望的结果
这种结构可以更广泛地应用,而不仅仅是单元测试。它适用于我们编写的所有自动化测试。此外,它也是用户故事接受标准的一种高度合格的形式。尝试清楚地识别测试的每个部分,尤其是给出的时间和时间。请记住,当部分仅包含经过测试的调用时是理想的。
使用夹具(fixtures )使您的测试设置清晰易读
测试设置通常是最复杂和最长的部分。随着给定部分的增长和可读性的降低,您应该立即做出反应。缺乏快速轻松设置测试的方法会促使开发人员进行不受控制的代码重复。
提供干净和灵活的测试设置方法的最佳方法之一是“夹具”模式。它只需要提取一个类,该类将包含准备好在测试中使用的预配置构建器的工厂方法。提到的测试使用 someLocation() 方法来创建 Location 对象。
public class LocationFixtures { public static Location.LocationBuilder someLocation() { return Location.builder() .status(LocationStatus.DRAFT) .id(“e3c2e50c-7cb3-11ea-bc55-0242ac130003”) .lat(51) .lng(21) .createdAt(Instant.parse(“2012-12-12T00:00:00Z”)) .owner(“trevornooah”) .name(“Corn Flower Museum”); } }
然后,可以自定义返回的构建器,以帮助您构建所需的任何测试用例。
使用描述性断言库
那些使用 JUnit 4 的读者仍然记得内置的断言库有多么有限。 在 JUnit 5 中它明显好转,但 AssertJ 库在这方面遥遥领先。
考虑以下测试和故障报告示例:
JUnit
@Test void testJunit() { final List<String> input = List.of("John", "Brad", "Trevor"); final List<String> expected = List.of("John", "Trevor"); assertIterableEquals(expected, input); } produces iterable contents differ at index [1], expected: <Trevor> but was: <Brad> AssertJ @Test void testAssertj() { final List<String> input = List.of("John", "Brad", "Trevor"); assertThat(input).containsExactly("John", "Trevor"); } produces Expecting: <["John", "Brad", "Trevor"]> to contain exactly (and in same order): <["John", "Trevor"]> but some elements were not expected: <["Brad"]>
防止你的测试断言不同的东西
该原则跨越了单个单元测试的边界,但随着代码库的增长变得至关重要。 它是所需测试套件特性的实际实现——“对于一个错误,一个单元测试应该失败”。
考虑以下方法:
public DetailedJsonLocation updateLocation(String locationId, JsonLocation jsonLocation, LoggedUser user) { log.info(“Updating location: {} by user: {} with data: {}”, locationId, user, jsonLocation); final Location location = locationsRepository.find(locationId); checkUserIsLocationOwner(location, user); final LocationStatus previousStatus = location.getStatus(); final Location updatedLocation = transactionOperations.execute(status -> { final Location foundLocation = locationsRepository.find(locationId); // … mapping code return foundLocation; }); if (previousStatus == AWAITING_PUBLICATION) { locationsGateway.sendPublicationRequestWithdrawn(updatedLocation.getId()); } return toDetailedJsonLocation(updatedLocation); }
此方法包含四个测试:
Test method | Asserted scope |
testUpdateLocationAwaitingForPublication |
Behavior unique to updating location that awaits for publication |
testUpdateDraftLocation |
Behavior unique to updating location that is a draft |
testUpdateLocation |
Behavior common to all location updates |
testUpdateLocationOwnerByOtherUser |
Behavior unique to update of the location owner by somebody else |
使用这种方法,如果位置更新过程中存在错误,我最终将只有一个失败的测试而不是四个。这简化了根本原因的分析。
实施集成测试
如上一节所述,集成测试旨在测试用作外部系统适配器的类的行为。确保您对所有集成都有准确的测试覆盖率。在本节中,我们将回顾一种测试微服务中实现的最常见集成的方法。
测试数据库集成
数据库肯定是最容易测试的集成,尤其是当您使用 Spring-Data 时,它为您提供了开箱即用的生成存储库实现。由于最近 Docker 的流行度增长,开发人员可以使用真实数据库进行测试,而不是像 H2 这样的内存数据库。该方法在 piko 中实现,您可以在 docker-compose.yml 和 application.yml 中找到数据库配置。
当您的应用程序调用一些复杂的查询,或者特别是动态查询时,您应该为该存储库编写集成测试。例如 piko-locations 调用使用参数和排序的查询 LocationsRepository#findByOwner。
通过重用我之前为单元测试创建的固定装置,我可以很容易地测试该查询(以及排序)。
@Test void testFindByOwner() { // given: final String owner = "owner:" + UUID.randomUUID().toString(); final Location location1 = locationsRepository.save( someLocation() .id(UUID.randomUUID().toString()) .createdAt(Instant.parse("2020-03-03T12:00:00Z")) .owner(owner) .build() ); final Location location2 = locationsRepository.save( someLocation() .id(UUID.randomUUID().toString()) .createdAt(Instant.parse("2020-03-03T13:00:00Z")) .owner(owner) .build() ); final Location location3 = locationsRepository.save( someLocation() .id(UUID.randomUUID().toString()) .owner("other-user") .build() ); // when: final List<Location> locations = locationsRepository.findByOwner(owner, Sort.by("createdAt"));
// then:
assertThat(locations).containsExactly(location1, location2); }
有用的注释:如果你的测试是@Transactional,你应该在测试调用之前和之后调用EntityManager.flush()。 Hibernate 不保证所有数据库指令都立即发送到数据库,而是在事务刷新期间发送。
这种行为有时会导致误报结果,其中测试通过只是因为 Hibernate 没有执行数据库语句,而是将它们缓存在内存中。
测试 HTTP 客户端和模拟服务器
使用 HTTP 协议通过网络进行通信是微服务集成的重要组成部分。毫不奇怪,为了进行彻底的测试,开发人员需要强大的工具来模拟外部服务。为此目的,最受欢迎的工具是 WireMock 库,它使存根服务器变得非常容易。
虽然 WireMock 用例的可能性令人印象深刻,但在“Piko”中,我们将自己限制为存根一个 AWS Cognito 端点以获取用户详细信息。
考虑到实现,准备一个专门的类来管理 WireMock 服务器和存根是非常方便的。在 piko-admin 应用程序中,您可以找到为此目的编写的 CognitoApi 类。
@Component @Slf4j public class CognitoApi implements Closeable { private final WireMockServer server; private final CognitoProperties cognitoProperties; @SneakyThrows
public void mockSuccessfulAdminGetUser(String username) {
final String json = “{…}”;
server.stubFor(
post(urlPathEqualTo(cognitoProperties.getEndpoint().getPath()))
.andMatching(request ->
request.header(“X-Amz-Target”).firstValue()
.equals(“AWSCognitoIdentityProviderService.AdminGetUser”)
? MatchResult.exactMatch()
: MatchResult.noMatch()
)
.willReturn(
aResponse()
.withStatus(200)
.withBody(json)
)
);
}
}
以这种方式准备的存根可以很容易地用于集成测试,只需一行代码:
@Test void testSendLocationPublishedNotification() throws Exception { // given: final String username = "johndoe-" + UUID.randomUUID().toString(); final String recipient = String.format("<%s@email.test>", username); cognitoApi.mockSuccessfulAdminGetUser(username); // ... }
测试与 SMTP 服务器的集成
交易电子邮件发送是应用程序中常见的业务需求之一。 虽然开发人员使用 Papercut 等本地 SMTP 服务器已经有很长时间了,但在自动化测试中使用类似概念仍然不常见。
在 Docker Hub 上有许多本地 SMTP 服务器,它们公开 API 以供编程使用。 其中之一是 schickling/mailcatcher。 在测试中发送电子邮件后,您需要做的就是调用 MailCatcher API 并进行断言。
@Test void testSendLocationPublishedNotification()
throws
Exception { // given: final String username = "johndoe-" + UUID.randomUUID().toString(); final String recipient = String.format("<%s@email.test>", username); cognitoApi.mockSuccessfulAdminGetUser(username); final DetailedJsonLocation location =
…
;
// when:
adminLocationsNotifications.sendLocationPublishedEmail(location);
// then:
final List<MessageSummary> messages = mailCatcherClient.listMessages();
final MessageSummary foundMessage = findByRecipient(messages, recipient);
assertThat(foundMessage).isNotNull();
final MailcatcherMessage message =
mailCatcherClient.fetchMessage(foundMessage.getId());
assertThat(message.getRecipients()).contains(recipient);
assertThat(message.getSender()).isEqualTo(String.format(“<%s>”,
notificationsProperties.getFromAddress()));
assertThat(message.getSubject()).isEqualTo(“Your location Corn Flower Museum was published”);
assertThat(message.getSource())
.contains(username)
.contains(location.getLocation().getName());
}
使用 MailcatcherClient 获取捕获的消息后,我可以检查电子邮件是否发送到正确的地址或从正确的地址发送,以及检查电子邮件内容是否包含所需的信息。
测试消息代理集成
微服务集成的第二种常见方式是使用一些消息代理。 如果使用 Spring Cloud Streams 向 Apache Kafka 发送和接收 Piko 异步消息。 除了简化消息生产者和消费者实现之外,它还公开了一个方便的 API 来测试消息传递。
在单元测试部分,您可能已经注意到调用负责将消息发送到 Kafka 主题的 LocationsGateway 的断言。
让我们考虑一个验证 LocationsGateway 发送正确消息的测试:
@BeforeEach void setUp() { locationEventsMessageCollector.dumpMessages(); } @Test void testSendPublicationRequestWithdrawn() { // given: final Location location = locationsRepository.save( someLocation() .id(UUID.randomUUID().toString()) .build() ); // when: locationsGateway.sendPublicationRequestWithdrawn(location.getId()); // then: final LocationMessage message = locationEventsMessageCollector.captureLastLocationMessage(); assertThat(message).isEqualTo( LocationMessage.builder() .id(location.getId()) .status(location.getStatus()) .event(LocationEventType.PUBLICATION_REQUEST_WITHDRAWN) .lat(location.getLat()) .lng(location.getLng()) .createdAt(location.getCreatedAt()) .owner(location.getOwner()) .name(location.getName()) .build() ); }
该测试使用 LocationEventsMessageCollector,它是一个非常薄的类,可以更方便地处理消息。 它使用 Spring Cloud Streams
public LocationMessage captureLastLocationMessage() { final Message<String> lastMessage = (Message<String>) messageCollector .forChannel(locationEventsBindings.outboundChannel()) .poll(); Objects.requireNonNull(lastMessage, “Could not capture last message for: “ + locationEventsBindings.OUT + ” binding”); return objectMapper.readValue(lastMessage.getPayload(), LocationMessage.class); }
实施组件测试
组件测试是您将在特定微服务代码中找到的最后一种测试类型。 它们的范围是最大的,它们确保整个业务流程在应用程序内部正确执行。
在编写组件测试时,应特别注意编写准确的断言。 虽然组件测试的范围很广,但您应该尽量保持您的断言肤浅,只断言整个操作成功并且调用了必要的函数。 无需检查每个功能和集成的行为,因为它已通过单元和集成测试进行验证。
使用 HTTP 调用的测试流程
我们的大部分业务流程都是通过调用 REST 端点触发的,因此 Spring Framework 有一个方便的工具来测试 HTTP 端点——MockMvc 也就不足为奇了。 让我们看看它是如何用于 Piko 系统中最重要的组件测试 - 验证位置发布过程的。
@Test void testPublishLocation() throws Exception {
// given:
final LoggedUser loggedUser = someLoggedUser("user-" + UUID.randomUUID().toString()) .build(); final Location location = locationsRepository.save( someLocation() .id(UUID.randomUUID().toString()) .owner(loggedUser.getUsername()) .build() ); cognitoApi.mockSuccessfulAdminGetUser(loggedUser.getUsername());
// when & then:
mvc.perform(put("/locations/{locationId}/status", location.getId()) .contentType(MediaType.APPLICATION_JSON) .content("{ \"status\": \"PUBLISHED\" }") .with(authenticatedUser(loggedUser))) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.status").value(LocationStatus.PUBLISHED.name())); // and: final Location foundLocation = locationsRepository.tryFind(location.getId()); assertThat(foundLocation).isNull(); final LocationMessage locationMessage = locationEventsMessageCollector.captureLastLocationMessage(); assertThat(locationMessage.getId()).isEqualTo(location.getId()); assertThat(locationMessage.getEvent()).isEqualTo(LocationEventType.LOCATION_PUBLISHED); final String expectedRecipient = String.format("<%s>", loggedUser.getEmail()); final List<MailCatcherClient.MessageSummary> capturedEmails = mailCatcherClient.listMessages(); assertThat(capturedEmails).anySatisfy(capturedEmail -> assertThat(capturedEmail.getRecipients()).contains(expectedRecipient) ); }
即使测试的“then”部分很长,你仍然可以注意到上面提到的“浅断言”原则。 通过观察业务流程结果来测试组件行为。 预期结果是:
- REST API 响应操作成功
- 位置已从 piko-admin 数据库中删除
- 应用程序已广播 LOCATION_PUBLISHED 事件
- 有一封电子邮件发送给用户
这种方法使该测试不受我们不需要在此处检查的可能的小而频繁的更改的影响。 所有这些都包含在不同的测试中。
Change example | Verification point |
Change in the endpoint response format | Unit test and another component test |
Change in the Kafka message format | Integration tests |
Change in the email logic | Integration test |
使用消息代理调用的测试流程
这可能不是特别直观,但是对传入消息做出反应的侦听器通常会调用业务流程,并且是组件测试的完美测试对象。 就像在 HTTP 端点测试中一样,我们想要测试整个接口层、业务逻辑和集成。
与 HTTP 端点的 MockMvc 类似,Spring Cloud Streams 公开了方便的 API 以将消息放入通道并路由到我们的应用程序。 让我们看一下在 piko-locations 中检查位置发布过程阶段的测试。
@Test void testLocationPublishedEvent() throws Exception { // given: final Location location = locationsRepository.save( someLocation() .id(UUID.randomUUID().toString()) .status(LocationStatus.AWAITING_PUBLICATION) .lastPublishedAt(null) .build() ); final LocationMessage message = toLocationMessage(location, LocationEventType.LOCATION_PUBLISHED);
// when:
locationEventsBindings.inboundChannel().send(
new
GenericMessage<>( objectMapper.writeValueAsString(message) ) );
// then:
final Location publishedLocation =
locationsRepository.find(location.getId());
assertThat(publishedLocation.getStatus()).isEqualTo(LocationStatus.PUBLISHED);
assertThat(publishedLocation.getLastPublishedAt()).isNotNull();
}
该测试用例更简单,但您也可以发现浅断言方法。使用 inboundChannel().send(...) 将消息发送到通道是完全同步的,因此我们的测试环境是安全且可重复的。
在 Maven 中组织测试执行
Apache Maven 使用两个生命周期阶段来执行测试:测试和验证。它们之间的区别在于默认为该阶段执行的插件。
在阶段测试中,执行插件 maven-surefire-plugin,它运行具有 Test 后缀的测试用例。
在验证阶段,执行插件 maven-failsafe-plugin,运行具有 IT 后缀的测试用例。
Maven FAQ 中介绍了它们之间的技术差异。
对于项目构建组织,基于“IoC 容器要求”标准区分测试而不是为每种测试类型设计不同的执行是实用的,因为它只会使您的构建更长。
最简单和最方便的设置是为您的单元测试添加后缀 Test 和 IT 的集成和组件测试。然后,默认配置将使 maven-surefire-plugin 立即进行单元测试,并使 maven-failsafe-plugin 进行集成和组件测试。
概括
在本文中,我们介绍了有助于确保开发的应用程序正常工作的测试类型。对于每种类型的测试,我们都回顾了有用的技术、模式、原则和工具来实现它们。
在高级别的组件测试中,您可以注意到我们所采取的措施相互配合得多么好,允许在测试中重用测试逻辑。
Used tool or pattern | Unit tests | Integration tests | Component tests |
Fixtures | yes | yes | yes |
Server stubs | no | yes | yes |
Message collectors | no | yes | yes |
所有类型的审查测试相互重叠一点,让我们在一个应用程序中完成代码验证过程。
- 44 次浏览
【自动化测试】微服务自动化测试简介
什么是微服务?
微服务 - 也称为微服务架构 - 是一种构建方式,它将应用程序构建为松散耦合服务的集合,具有完整的业务功能。微服务架构允许连续交付/部署大型复杂应用程序。本文将概述自动微服务测试工具和最佳实践。
它还使组织能够发展其技术堆栈。微服务逐渐用于创建更大,更复杂的应用程序,这些应用程序作为较小服务的组合得到更好的开发和管理,这些服务可以协同工作以实现更重要的应用程序范围的功能。
大而复杂的应用程序由更直接和独立的程序组成,这些程序可由它们自己执行。这些小程序聚集在一起,提供了大型单片应用程序的所有功能。
什么是微服务测试?
所采用的任何测试策略都应旨在覆盖每层和服务层之间,同时保持轻量级。 MicroServices测试需要替代方法 - 测试团队应该制定策略,以便在设计阶段开始测试微服务。测试团队最初参与设计/架构小组,以了解功能,使用情况和未覆盖的界面,这些都将对您有所帮助。除上述内容外,测试人员还应确保所有接口都是通用的,以便其他系统/服务可以毫无障碍地使用。
由于需要自动化所有内容,因此请使用Micro Services测试自动化工具。这些工具有助于验证每个独立服务单元的功能,并通过组合多个这些微服务来执行集成测试。
微服务的自动化测试级别
- 单元测试 - 这是测试单个微服务测试单元的内部工作。这些可以使用自动单元测试框架在每个编程级别自动化。
- 合同测试 - 这是为了测试每个微服务单元是否遵守所建立的合同中提供的给定功能。这里每个服务组件都单独作为黑盒测试。在合同测试中,即使服务发生变化,服务也应该为相同的给定输入提供相同的结果。 MicroService Architecture中的每项服务都可以在更长的时间内稳健运行。它保证在不影响现有使用者的情况下为每项服务添加新功能。
- 集成测试 - 检查多个服务是否相互通信,并提供服务功能级别文档中给出的所需结果。这可以是整体微服务架构集成测试,也可以只占用架构和测试的子区域。
- UI功能测试 - 在此,与UI集成的服务和通过UI完成的测试,其中通过UI提供MicroServices所需的输入,并通过UI测试所需的输出。
对于所有这些类型的测试,可以执行自动测试。
对于单元测试,使用基于NUnit或JUnit的单元测试框架,以较少的QA参与自动化测试。
对于合同测试,QA测试自动化工程师参与。此测试在每个服务单元中执行,通过隔离它并命中服务的单个URI。合同中给出的函数将使用测试自动化框架内的自动化脚本集进行测试。
集成测试通过合同测试中使用的相同工具集自动化。这里唯一的区别是将考虑不止一个服务单元,并且自动化脚本触发功能以在这些处理器内提供通信,其中验证了所需的输出。这里的自动化测试还将验证通信消息格式以及处理器之间链接的任何数据库。
UI功能测试使用自动化测试工具自动化,如UFT,Selenium或任何其他基于UI的自动化工具。
在进行Micro Service Automated测试时,可以集成多个工具或框架。将API自动化测试工具框架和基于UI的自动化测试工具框架集成在一起也是一种很好的做法。这是测试自动化的未来。大多数组织使用全局混合测试自动化框架,而不是维护单独的框架。
如何自动化测试工作?
单独测试每项服务
测试自动化是测试离散微服务的工具。很容易创建一个简单的测试工具,重复调用服务并将一组已知输入与预期输出进行比较。无论如何,所有这一切,都不会在测试中变得异常。它将释放测试团队专注于更复杂的测试。
测试应用程序的不同功能部分
在认识到应用程序中的关键功能元素后,应该尝试以传统方式进行集成测试的方式对其进行测试。这里测试自动化的优势很明显。每次其中一个微服务刷新时,都会快速构建测试脚本。将新代码的输出与先前的输出进行比较,快速确定是否有任何变化。
不要在小型设置中进行测试
一些管理人员有能力保留测试组的资源。但是,对于基于微服务的应用程序,这会适得其反。与尝试制作小型本地登台环境以测试代码相反,应该考虑利用基于云的测试。这里动态分配资源作为测试需要它们,在测试完成后释放它们。因此,测试自动化在这里不会直接提供帮助。
尝试跨不同的设置进行测试
建议使用多个环境来测试代码,类似于Web应用程序的跨浏览器测试。我们的想法是将代码暴露给库类型,底层硬件等可能在部署到生产时影响它的任何微小变化。实现此目的的一种方法可能是在运行中制作登台环境。利用Kubernetes,可以想象创建一个测试环境,使用来自已知源的数据填充它,加载代码然后运行测试。卓越之处在于每次重新创建环境时都会自动暴露于可能存在的任何差异。当然,另一方面是诊断任何错误的根本原因变得更加困难。
尽可能使用Canary测试
金丝雀测试是一种方法,其中一小部分用户呈现代码中的变化,并将他们的经验与仍然运行旧代码的用户的体验进行对比。该方法对于测试微服务特别有用。它使用监控来调查变更的影响。它可以通过采用一次一个服务实例更新的策略来快速判断错误率,服务负载,响应能力和类似指标,从而判断新代码是否会产生负面影响。自动做金丝雀测试。
金丝雀测试是一种方法,在这种方法中,客户稍微安排一下代码的变化,对比体验以及那些运行旧代码的客户的遭遇。这种方法对测试微服务特别有用。它利用检查来调查变化的影响。它查看了错误率,利益负担,响应性和比较测量,以揭示新代码是否具有不利影响。通过采用一个程序,当一个管理案例同时令人耳目一新时,可以毫不费力地进行,从而进行金丝雀测试。
人工智能测试
AI或人工智能用于完全自动化微服务应用程序的Canary测试。深度学习等AI方法可识别新代码激活的更改和问题。很少有用户转移到新框架,AI将经验与现有用户的体验进行了比较。由于这可以自动实现,因此它会取代循环中的人。
可调试代码
编写可调试代码包括稍后进行查询的能力,这反过来涉及 -
正确的代码检测。
了解所选择的可观察性安排(无论是指标还是日志或独特的案例追踪器或痕迹或这些的混合)及其优缺点。
根据给定服务的要求,依赖性的操作怪癖和良好的工程直觉,选择最佳可观察性的能力。
微服务自动化测试的好处
测试微服务有以下好处 -
- 激励更好地隔离服务和设计更好的系统。
- 它对程序员施加了一定的设计压力,以便以易于使用的方式构建API。
- 测试充当应用程序公开的API的精彩文档。
- 单独测试每项服务。
- 测试应用程序的不同功能部分。
- 监控以评估变更的影响。
- 监控应用程序的持续性能。
为什么微服务的自动测试很重要?
由于以下原因,微服务测试很重要 -
解耦
每个功能都松散耦合,以帮助SaaS / SOA架构。 MicroServices通过网络分散在各个平台上,并通过REST over HTTP进行集成。
可维护性
每项服务都是独立维护,升级和测试的,这是SaaS架构的基本要求。这使得微服务成为持续交付的必要推动者,支持频繁发布,同时提供高系统可用性和稳定性。
可扩展性
每个微服务根据用途自动缩放。每个服务都根据资源需求部署在自治硬件上,这在传统的单片设计方法中是不可能的。
可用性
每个微服务都可以自主设计和部署,以实现故障转移和容错。例如,内存和CPU使用等问题在本地传递,而不同的服务通常继续工作。
如何对微服务进行自动化测试?
有五种策略用于成功测试微服务。
文档优先策略
遵循文档第一种方法,大多数文档都是Git中的markdown。 API文档保持开源,所以它都是公开的。此时,在任何人编写任何API更改或不同的API之前,首先刷新文档,调查该更改,以确保它使用完全记录的API约定和标准进行调整,并确保不存在重大更改。确保它符合命名约定等等。
完整的堆栈内置策略
整个堆栈一体化策略需要在本地复制云环境并在一个流浪者实例中测试所有内容(“$ vagrant up”)。
AWS测试策略
第三种方法涉及启动Amazon Web Services(AWS)框架以部署和运行测试。对于完整堆栈盒内策略,这是一种更具适应性的方法。有些人将此称为个人部署[策略],每个人都拥有自己的AWS账户。在大约十分钟内将工作站上的代码推送到AWS,然后像真实系统一样运行它。
共享测试实例策略
第四种策略是完整堆栈内置和AWS测试之间的交叉品种。这是因为它涉及在自己的本地站工作,同时利用微服务的不同共享实例在测试期间指向本地环境。有些运行微服务的不同实例仅用于测试本地构建。但是,本地构建器将指向在Google基础结构中运行的测试映像解析器。
存根服务策略
微服务的标记或“存根”表现得像正确的服务,并在服务发现中作为真实服务进行宣传,但却是虚拟模仿。例如,测试服务可能要求服务意识到用户执行一组任务。使用存根服务,假设用户任务已经发生,而没有随之而来的典型复杂性。与在整体上运行服务相比,这种方法更轻量级。
自动化微服务测试的最佳实践
隔离测试
微服务很难测试,因为有许多独立服务以许多(通常是未预料到的)方式与其他独立服务进行通信。开始测试自动化工作的一个好地方是直接测试特定微服务的功能。通常,通过使用REST API与服务进行通信以及一些模拟来快速完成,以便单独测试服务,而无需与其他服务进行任何集成。
签订合同
几乎不可能知道消费者使用服务的所有方式。通过消费者驱动的交易,消费者必须提供一套测试,以确定所需的交互类型和格式。然后服务将同意合同并确保合同没有被破坏。这规定了其他服务的条件。此方法还可以验证交易是否在构建时完成。像Pact这样的工具可以更好地理解如何实现这种类型的功能来开发和测试微服务。一旦有了消费者驱动的合同流程,测试微服务的下一步就是转移到以前被禁止的生产世界。
转右 (Shift-Right )- 投入生产
在DevOps,微服务领域,生产测试成为整体质量计划的必要条件。通过基于微服务架构的流动,移动关系,如何确定许多服务将扩展的方式?如何提前了解服务的行为?如何测试此漏洞?答案是开始在生产中进行测试。
监控和警报
建立密钥检查和警报系统,并在生产中进行跟踪至关重要。如果其中一项服务出现故障或无响应,请立即显示。通过在监控的帮助下识别生产过程中的问题,在用户甚至知道存在问题之前,通常可以轻松地返回到上一个已知的优质服务版本。
最佳自动化微服务测试工具
- Hoverfly - 模拟API延迟和故障。
- Vagrant - 构建和维护可移植的虚拟软件开发环境。
- 录像机 - 一种单元测试工具。
- 契约 - 框架由消费者驱动的合同测试。
- Apiary - API文档工具。
- API蓝图 - 设计和原型API。
- Swagger - 设计和原型API。
原文:https://www.xenonstack.com/insights/what-is-automated-testing-for-microservices/
本文:http://pub.intelligentx.net/introduction-automated-testing-microservices
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 96 次浏览
【软件测试】Pact最佳实践:消费者--->使用Pact进行合同测试,而不是生产者的功能测试
- 功能测试是关于确保提供者通过请求做正确的事情。这些测试属于提供程序代码库,而编写它们并不是消费者团队的工作。
- 合同测试旨在确保您的消费者团队和提供者团队对每种可能方案中的请求和响应有共同的理解。
- 契约测试应该关注
暴露消费者如何创建请求或处理响应的错误
暴露了对提供者如何回应的误解
- 契约测试不应该关注
暴露提供程序中的错误(尽管这可能是副产品)
您可以在此处阅读有关合同和功能测试之间差异的更多信息。
计算出测试或不测试内容的经验法则是 - 如果我不包括这种情况,那么消费者中的哪些错误或者对提供者如何响应的误解可能会被遗漏。如果答案是否定的,请不要包括它。
使用Pact进行隔离(单元)测试
- 作为模拟(在测试后验证对模拟的调用)不是存根(对存根的调用未经验证)。使用Pact作为存根会破坏使用Pacts的目的。
- 对于负责从Consumer应用程序到Provider应用程序进行HTTP调用的类的隔离测试(即单元测试),而不是整个消费者代码库的集成测试。
- 仔细地,在您的消费者代码库中进行任何类型的功能或集成测试。
为什么?
如果您使用完全匹配的Pact进行集成测试,那么您将会疯狂。由于Pact会检查每个传出路径,JSON节点,查询参数和标头,因此您将进行非常脆弱的Consumer测试。您最终还会遇到需要在提供商方面进行验证的笛卡尔互动。这将增加您花费在提交者测试通过上的时间,而不会有用地增加测试覆盖率。
仔细考虑如何将它用于非隔离测试(功能,集成测试)
保持孤立,完全匹配测试。这些将确保您将域对象中的正确数据映射到请求中。
对于集成测试,为请求使用松散的,基于类型的匹配以避免脆弱,并将设置拉出到可以在测试之间共享的方法,这样您就不会有一百万次交互来验证(这将有所帮助,因为“契约”中的交互集合就像一个集合,并丢弃完全重复的内容。
如果您不关心验证您的交互,可以使用Webmock之类的东西进行集成测试,并使用共享fixture来处理这些测试和Pact测试之间的请求/响应,以确保您进行某种程度的验证。
通过URL向提供商提供最新协议
请参阅在Consumer和Provider之间共享pacts以获取实现此目的的选项。
确保对提供程序的所有调用都通过已使用Pact测试的类
不要直接在您的Consumer应用程序中手动创建任何HTTP请求。通过客户端类(一个独立负责处理与提供者的HTTP交互的类)进行测试,可以更加确保您的消费者应用程序将创建您认为应该的HTTP请求。
确保您在其他测试中使用的模型实际上可以从您期望的响应中创建
当然,您已经检查过您的客户端将HTTP响应反序列化到您期望的Alligator中,但是您需要确保在另一个测试中创建Alligator时,使用有效属性创建它(例如,Alligator的last_login_time a时间还是日期时间?)。一种方法是使用工厂或夹具为所有测试创建模型。有关更详细的说明,请参阅此要点。
小心垃圾输入,垃圾输出PUT / POST / PATCH
每个交互都是隔离测试的,这意味着您不能执行PUT / POST / PATCH,然后使用GET跟踪它以确保您发送的值实际上由提供者成功读取。例如,如果您有一个可选的姓氏字段,并且您发送了lastname,那么提供者很可能会忽略错误名称字段,并返回200,无法提醒您,您的姓氏已经转到了大/ dev /在天空中无效。
为了确保您没有Garbage In Garbage Out情况,期望响应主体包含新更新的资源值,并且一切都会很好。
如果出于性能原因,您不希望在响应中包含更新的资源,另一种避免GIGO的方法是在GET响应主体和PUT / POST请求主体之间使用共享夹具。这样,您就知道您正在PUTing或POSTing的字段与您将要获取的字段相同。
使用can-i-deploy
使用Pact Broker CLI的can-i-deploy功能。如果您正在部署的消费者版本与其所有提供商兼容,它将为您提供明确的答案。
- 31 次浏览
软件测试
- 75 次浏览
[敏捷软件测试】应对敏捷时代的软件测试挑战
挣扎是真的
由于软件开发领域的重大转变,测试行业正在经历快速而深远的变革。软件的开发和部署速度比以往任何时候都快,这为测试人员带来了一系列新的挑战。过去为质量保证部门服务的传统程序和技术已不再适用。
你将学到什么
- 在本指南中,我们将软件开发中的两位思想领袖聚集在一起,以提供有关测试未来和成功团队如何随着时代变化而发展的观点。
里面是什么?
- 测试人员如何获得在敏捷环境中有效规划和测试所需的洞察力。
- 关于如何找到正确的测试方法组合的指导 - 自动化,探索性和用户验收测试。
- 探索性测试如何帮助解决现代开发,持续部署和快速反馈循环的压力。
- 何时以及如何使用探索性测试作为开发过程的一部分。
- 最好的测试人员如何将测试过程分解为一个简单的三个问题:为什么,什么以及如何?
原文:https://www.qasymphony.com/landing-pages/tackling-testing-challenges-in-the-agile-era/
- 38 次浏览
【Kafka】测试Kafka:我是如何学习东西的
当我开始测试Kafka的任务时,我意识到我有很多要理解的主题。在任务期间,我花时间积极学习这些主题,以及在任务期间出现的任何其他主题,例如AWS。
这篇博文介绍了各种主题。它不会详细介绍其中任何一个(我可能会在其他博客文章中介绍一些内容),而是我会专注于我如何学习这个项目的一部分。
- Kafka:这可能是一个明显的主题,但我需要了解Kafka与其可靠性,弹性,可扩展性相关的特定方面,并找到监控其行为的方法。我最后还学习了如何编写Kafka客户端,实现和配置SASL_SSL安全性以及如何配置它。
- VMWare:VMWare Enterprise技术将用于某些运行时环境。多年来我一直没有使用VMWare,并决定学习如何在几个小而又充满代表性的服务器上配置,监控和运行ESXi。这将使我既可以在客户端环境中工作,也可以独立地运行其他测试,而不是等待足够的环境和VM按需提供(由于内部流程和组织结构,企业往往移动得更慢)。
- 如何'性能测试'Kafka:我们有几个想法,并且发现Kafka包含了一个“性能测试”实用程序。我们需要了解该实用程序如何生成消息和测量性能。它也可能不是最适合项目需求的工具。
- 如何降低系统性能并暴露系统中的缺陷会对项目中使用Kafka的价值产生不利影响。如果可以直接访问机器和测试环境,则断开网络电缆,查杀进程等非常容易。但是,我们需要能够引入更复杂的故障条件,并且能够远程注入故障。
这些是我在任务开始时所知道的。还出现了几个,包括:
- 在AWS中创建测试环境。这包括在VPC之间创建区域间对等,创建Kafka和Zookeeper集群,以及多个负载生成器和负载消费者实例来执行各种性能和负载测试。虽然有各种“快速入门”,包括用于部署Kafka集群的快速入门https://github.com/aws-quickstart/quickstart-confluent-kafka;最后我们不得不创建自…,堡垒主机和VPC。快速入门脚本经常失败,然后环境在失败后需要进行额外的清理。
- Jepsen和其他类似的混沌生成工具。 Jepsen在几个主要版本之前测试了Kafka https://aphyr.com/posts/293-jepsen-kafka这些工具是可用的和开源的,但它们是否适合我们的环境和技能组合?
- 在我们最终确定修改开源独立负载生成器并编写互惠负载消费者之前,各种开源负载生成器,包括与jmeter集成的2个。
- Linux实用程序:我们广泛使用它来处理环境和自动化测试。类似地,在一些较大的体积负载测试之后,我们编写了实用程序脚本来监视,清理和重置集群和环境。
- 启用主题自动创建的细微差别和影响。
- KIP(卡夫卡改进提案):
- 报告和分析:客户对报告内容以及报告方式有特别的期望。一些工具没有以足够的粒度提供结果,例如他们只提供“平均值”,我们需要校准工具,以便我们可以信任他们发出的数字。
注意:以下按主题或概念排序,而不是按时间顺序排序。
我是如何学习与测试Kafka相关的东西的
我知道从一开始就要学到很多东西。因此,我决定在合同签订之前投入时间和金钱,这样我就可以立即投入。值得庆幸的是,所有软件都是免费提供的,并且通常是开源的(这意味着我们可以阅读代码以帮助理解它,甚至修改它以帮助我们完成工作和学习)。
大多数学习都沉浸在实践中,我和我的同事会在各种测试环境中尝试,并通过实践,观察和实验来学习。 (我将在这里提到一些测试环境,并可能在其他博客文章中更详细地介绍方面。)
我发现并且第一次感谢在线课程的支付范围,深度和价值。虽然他们不一定像参加商业培训课程一样好,房间里有导师并且可以立即获得建议,但范围,价格和可用性是一个启示,我购买的所有课程的财务成本低于65英镑(90美元)。
阅读也很关键,网上有很多博客文章和文章,包括直接参与开发和测试Kafka的人的几篇重要文章。我还搜索了经过同行评审的学术文章。我只找到了一对 - 可惜的是,书面的学术研究是对商业和/或个人非正式报道的一种不可思议的补充。
我们花了很多时间阅读源代码,然后修改我们希望在适应后适合的代码。值得庆幸的是,客户同意我们可以公开提供我们的非机密工作,并在宽松的开源和创意公共许可下提供。
Udemy
几年前我第一次使用udemy课程来尝试学习几种技术。当时我没有得到或得到很多价值,但经常打折的价格足够低,我不介意太多。相比之下,这次我发现udemy课程非常有价值且相关。 udemy提供的课程的丰富性,范围和深度令人难以置信,并且有足够的优质课程可用于相关主题(特别是在Kafka,AWS和较小程度上的VMWare),以便能够快速,实用地取得进展。学习这些关键主题的方方面面。
我真的很感激能够不仅观看几个介绍性视频,还能看到我发现的每个潜在比赛中更高级主题的例子。观看这些是免费的,并不需要很长的时间,并使我能够很好地了解主持人的方法和材料是否值得我给我知道和我想要实现的目标。
如果我认为我至少要学习该课程中的几个具体项目,我就采取了支付课程费用的方法。与他们在我的意识和理解中释放的知识的潜在价值相比,成本很小。
有时,即使是看似做得不好的课程,也有助于我理解哪些概念很容易混淆和/或很难理解。如果主持人感到困惑 - 也许我也会感到困惑????那就是说,对我来说最有价值的来自以下与我特别相关的课程:
https://www.udemy.com/apache-kafka/learn/v4/overview
https://www.udemy.com/kafka-cluster-setup/learn/v4/overview
https://www.udemy.com/apache-kafka-security/learn/v4/overview
https://www.udemy.com/aws-certified-solutions-architect-associate/learn…
https://www.udemy.com/vmwarecloudaws/learn/v4/overview
前三个课程由同一位主持人Stephane Maarek领导。他特别有魅力。当我通过udemy的平台向他发送问题时,他也很有帮助和反应灵敏。
发表文章和博客文章
我不会在这里列出文章或博客文章。有太多,我怀疑过多的链接会对你有多大帮助。在学习方面,一些主要挑战在于确定这些文章是否与我们正在测试的Kafka版本实现的目标相关。例如,许多在Kafka版本0.10之前编写的文章不再具有相关性,并且复制测试和示例有时太耗时而无法证明所需的时间。
此外,项目想要使用Kafka的方式很少被覆盖,我们发现我们需要使用的一些关键配置设置极大地改变了Kafka的行为,这再次意味着许多文章和博客文章没有直接应用。
我使用了一个名为Zotero的软件工具来管理我的笔记和参考资料(我已经使用了几年作为我的博士研究的一部分)并且在那里记录了超过100篇已识别的文章。我在作业期间读了很多文章,可能多达1000篇。
学术研究
我发现的最好的文章比较了Kafka和RabbitMQ在工业研究环境中的作用。有几个版本可用。同行评审的文章可以在https://doi.org/10.1145/3093742.3093908找到,但是除非您有合适的订阅,否则您可能需要为此版本付费。最新版本似乎是https://arxiv.org/abs/1709.00333v1,可以免费下载和阅读。
测试环境
在这里,我会简短。我计划稍后深入介绍测试环境。我们的测试环境包括Raspberry Pi集群(使用MirrorMaker等进行复制),Docker容器,运行ESXi的廉价物理机架式服务器以及多个AWS环境。 Docker和AWS都经常被引用,例如我之前提到的udemy kafka课程使用AWS作为他们的机器。
原文: http://blog.bettersoftwaretesting.com/2018/04/testing-kafka-how-i-learned-stuff/
- 37 次浏览
【合约测试】Pact 101 - Pact和消费者驱动的合同测试入门
所以你听说过Pact并希望开始。本指南应该有助于您朝着正确的方向前进。
什么是契约?
Pact系列测试框架(Pact-JVM,Pact Ruby,Pact .NET,Pact Go,Pact.js,Pact Swift等)为依赖系统之间的消费者驱动合同测试提供支持,其中集成基于HTTP(或消息)某些实现的队列)。它们对于μ服务特别有用,在这些服务中可能存在大量相互依赖的服务,并且集成测试很快变得不可行。
在我们深入了解Pact之前,您需要了解消费者驱动的合同。
什么是消费者驱动的合同?
消费者驱动的合同是一种模式或方法,其中相互依赖的服务之间的合同是从服务消费者的角度设计的。它的主要文章是消费者驱动的合同:服务进化模式,但它在技术方面有点过时(它谈论了很多关于XML和模式)。但是文章中表达的概念与我们今天构建的计算机系统有关。
我发现很多时候构建μ服务或内部API的团队都遵循与外部或公共API相同的思路。服务提供商或API团队会考虑其服务的任何消费者需要的所有内容(在此过程中做出许多假设),然后提供服务以及如何使用它的文档。他们建立它并希望消费者来。
当他们稍后需要更改它时,他们会进行更改,然后将其与所有消费者需要遵循的说明一起发布以使用更新的API。它们可能包含多个版本的服务,以保护消费者免受重大变化的影响。
我目睹了第一手开发和使用API的两个团队。 在构建消费者和提供者之后,他们花了很多天才在集成测试环境中进行交互,因为消费者团队认为API将基于发布JSON文档(它是从Web浏览器调用),而 提供程序团队实现了application / x-www-form-urlencoded POST API。
但具有讽刺意味的是,对于内部API和服务而言,要弄清楚服务的所有消费者是谁以及他们的要求是什么并不难。 大多数时候,他们都在同一个组织工作。
消费者驱动的合同扭转了这一切。 交互合同由服务的消费者开发。
这种方法的好处是,您知道您的服务的所有消费者是谁,您将知道何时进行重大更改,以便更容易进行更改,合同也是一种文档形式。 其次,您将确切地知道需要提供哪些功能,以便您可以实现消费者所需的正确服务,并遵循YAGNI原则。
交互的发展始于消费者方面,希望通过测试。 消费者团队定义交互合同并根据合同实现服务使用者。
然后将此合同提供给提供者团队(在某些情况下,它是同一个团队),并且实施提供者服务以履行合同。
开始时我需要做什么?
大多数信息可以在Github页面上找到,用于各种Pact实现。 Ruby Pact在wiki中有很多信息。
- Ruby Pact: https://github.com/realestate-com-au/pact
- JVM Pact: https://github.com/DiUS/pact-jvm
- .Net Pact: https://github.com/SEEK-Jobs/pact-net
- Pact Go: https://github.com/pact-foundation/pact-go
- Pact.js: https://github.com/pact-foundation/pact-js
- Pact Swift: https://github.com/DiUS/pact-consumer-swift
- Pact Python: https://github.com/pact-foundation/pact-python
特别是,要了解Pact的工作原理,请阅读:https://github.com/realestate-com-au/pact#how-does-it-work。
从消费者测试开始
这完全是关于消费者的,所以从那里开始。支持许多测试框架,因此根据您使用的测试工具,请阅读相关文档。
对于Ruby和RSpec,请阅读使用pacts简化微服务测试的示例。
对于基于JVM的测试框架(JUnit,Groovy等),请查看https://github.com/DiUS/pact-jvm#service-consumers。 JUnit似乎是最受欢迎的。有很多示例测试。
一旦运行了消费者测试,就应该生成pact文件。这些是消费者驱动合同意义上的合同。您可以通过多种方式发布这些文件。常见的方法是将它们提交到源存储库,将它们上载到文件服务器,将它们存储为CI构建中的工件或将它们上载到Pact Broker。
验证您的提供商
该方法的后半部分是验证您的提供商实际上是否符合消费者的期望。对于已实现消费者测试的每个消费者,您应该在某处发布pact文件。通常,您希望在其CI构建中验证您的提供商,以便您知道更改何时破坏了与消费者的交互,并且您还将知道您受影响的消费者。
给定一组已发布的pact文件,有两种主要方法可以验证您的提供程序是否遵守pact文件中封装的合同。
使用构建插件来验证协议
第一种方法是使用构建插件,该插件可以在pact文件中针对您的提供者执行请求。在某些情况下(如Ruby Rake任务),提供程序从测试工具(Rack Test for ruby)中启动,重放请求,然后将响应与pact文件的预期响应进行比较。在其他情况下(如Maven和Gradle插件),实际的提供程序需要运行,构建插件会向正在运行的提供程序发出实际请求。
有关为Ruby提供程序使用Ruby Rake任务的示例,请阅读使用pacts简化微服务测试的“提供程序”部分。
JVM构建插件(Maven,Gradle,Leiningen和SBT)的自述文件包含有关如何使用这些工具的更多信息。在大多数情况下,您需要能够事先启动您的提供程序并在之后停止它,并且有办法提供协议所需的测试数据。有关更多信息,请参阅Pact-JVM自述文件的“服务提供程序”部分。
Pact具有状态更改机制,用于在验证测试运行期间控制提供程序的状态。本质上,这是一个可以在每个请求之前调用的钩子,其中描述了提供者为了能够成功处理请求而需要的预期状态。例如“用户Andy应该存在”或“订单表应该为空”。 Ruby实现允许定义设置和拆除块,而JVM构建插件允许定义状态更改URL,该URL将在实际请求发出之前接收具有状态描述的POST请求。
使用测试框架来验证契约
使用某些构建插件的最大缺点是,您需要让您的提供程序运行,并且您需要能够设置测试数据。这涉及预先加载所有契约所需的夹具数据,或者使用状态更改机制来动态更改提供者的状态。这两种方法都需要相当多的编排,尤其是在CI环境中。
由于社区贡献,Pact JUnit提供程序运行程序可供使用基于JVM的提供程序的人员使用。它允许您仅处理提供者处理请求的部分提供者代码,并且您可以使用JUnit设置和拆除机制以及状态注释标记来设置协议所需的数据。您也可以使用标准的模拟框架来存根依赖关系,尽管我会添加一个警告,以确保您不会影响您的模拟和存根的行为。自述文件包含更多信息。
我在哪里可以获得支持?
与大多数开源项目一样,Pact拥有一个充满活力的在线社区。有一个用于Ruby和JVM版本的Google组和Gitter通道(单击Github页面上的Gitter图像)。我建议您在那里搜索或发布您的问题,有人肯定会回答。
原文:https://dius.com.au/2016/02/03/microservices-pact/
本文:http://pub.intelligentx.net/node/524
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 46 次浏览
【合约测试】合同测试无服务器和异步应用程序 - 第2部分
我们现在已进入无服务器功能的时代,我们不再需要担心代码的运行位置和方式。别人会为我们担心(以名义价格),我们只需要关心我们的职能,以实现他们的命运,并成为他们所能做的一切。这提出了一些与我们的测试实践相关的问题。好吧,它也提出了其他问题,但是对于这篇重要的博客文章而言。
从技术上讲,仍有讨厌的服务器。我们无法看到我们的功能正在运行的数据中心,或者在什么计算机上,或者实际上,如果它们在计算机或其他人的冰箱上运行。但是我们的函数以异步方式相互交互,将事件作为输入消耗并生成输出,这反过来导致消耗更多事件。我们在消息队列中测试与消费者和提供者的合同所做的所有想法都可以在这里同样适用。
无服务器世界中的合同测试
对于这篇文章,我们将使用AWS Lambda函数作为示例。我假设一切都适用于Google Cloud Functions和Microsoft Azure功能,但我从未使用过。
我使用的第一个Lambda函数帮助我们打破了传统单片系统的功能。我们需要添加一个功能,通过电子邮件将PDF发送给客户的客户,我们不希望必须完成大型应用程序的发布过程。解决方案是将遗留系统中最小的代码放在遗留系统中,一旦数据耗尽,我们就可以使用所有AWS服务并启用持续交付管道。
在这种情况下,我们选择更新遗留系统以编写包含S3存储桶所需的所有必要数据的JSON文件。 这是一个小小的改变,给了我们很大的灵活性。 从那里(一旦部署了更改),我们可以连接一个函数来响应存储桶事件,将PDF渲染回存储桶,然后让另一个函数响应这些事件以通过电子邮件发送它。 这真是太棒了。
直到有人没有通过电子邮件获取他们的PDF。
原始系统中模型类的一个小变化导致JSON格式发生变化,导致lambda函数失败。 没有工作的lambda函数意味着没有PDF,这反过来导致没有lambda函数调用和没有电子邮件。 没有警报意味着没有人在Cloud Watch日志中看到错误日志。 事实证明,交付经理因缺乏交付而感到非常不安。 谁知道?
看起来合同测试是有序的。 我们只需要确定合同的位置。
在这种情况下,我们可以使用与上一篇文章中描述的相同的Message Pact解决方案来测试此合同。 S3存储桶和S3事件只是传输机制。 实际合同介于我们添加到遗留系统的代码和lambda函数之间。 如果我们一直在关注,我们应该注意到将JSON文件写入S3存储桶正在跨越上下文边界,我们应该进行合同测试。 我们也应该对我们的日志发出警报。 而且喝得少,运动量更多,吃得更健康。 但这是狂野的无服务器西部的日子。 当然,这当然不是借口。
下面是使用Pact的基于异步消息的合同测试流程图:
Lambda函数是JSON消息的使用者,遗留应用程序是提供者。嗯,它比那复杂一点。该消息不是实际的JSON数据,而是包含对存储在S3存储桶上的JSON文件的引用的S3事件。 AWS S3服务和Lambda执行服务之间还有一个HTTP请求,但我们可以只关注更高级别,并假设我们通过S3存储桶传递一个异步S3事件传递给我们的函数。
Lambda函数消费者
大多数Lambda函数可能都是用Node.js编写的,但在这种情况下,我们精通Java PDF生成库,因此我们选择将其编写为Groovy JVM函数。使用基于JVM的Lambda函数的开销是可以的,因为只要PDF在下一个工作日开始时通过电子邮件发送,该函数响应事件的时间并不重要。然后我们也可以使用Spock编写测试和Pact-JVM来测试它。
消费者Pact测试基于我们的JSON数据有效负载定义消息交互,并将其包装在S3事件的模拟中。它看起来像这样:
class PoToPdfHandlerPactSpec extends Specification { // our Lambda function handler private PoToPdfHandler handler // mock of the service which will generate the PDF file private PDFGenerator pdfGenerator // mock of the service that will fetch the JSON from the S3 bucket private PurchaseOrderService orderService def setup() { pdfGenerator = Mock() orderService = Mock() handler = new PoToPdfHandler(pdfGenerator, orderService) } def 'has a contract with the Big Bad Legacy App with regards to POs'() { given: def poStream = new PactMessageBuilder().call { serviceConsumer 'PoToPdfHandlerLambdaFunction' hasPactWith 'Big Bad Legacy App' given('there is a valid address and email') expectsToReceive 'a purchase order in json format' withContent(contentType: 'application/json') { supplierName string('Test Supplier') supplierOrderId identifier() processingCentreId identifier() orderDate timestamp('yyyy-MM-dd\'T\'HH:mm:ss') lineItems minLike(1) { productCode regexp(~/\d+/, '000011') productDescription string('JIM BEAM WHITE LABEL COLA') // oh, yeah quantityOrdered integer(20) } summary { orderTotalExTax decimal(2000.0) orderTotalIncTax decimal(2200.0) } supplierEmail string('TestSupplier@wild-serverless-west.com') senderEmail string('buyers@wild-serverless-west.com') } } def bucket = 'testbucket' def inputKey = 'po.json' def outputKey = 'po.pdf' // We need to mock out the AWS objects for this test, // as the handler will use the AWS SDK to fetch the // actual message from the S3 bucket using the information // from the event we receive Context context = [:] as Context def poBytes def mockS3Object = Mock(S3Object) { getObjectContent() >> { new S3ObjectInputStream( new ByteArrayInputStream(poBytes), null) } } // The event JSON we will receive def eventJson = [ records: [ [s3: [bucket: [name: bucket], object: [key: inputKey]]] ] ] def event = Gson.newInstance().fromJson(JsonOutput.toJson(eventJson), S3Event) when: poStream.run { Message message -> // The actual JSON from the message will be wrapped in an input stream // which will be read by our handler via the mocked AWS SDK call poBytes = message.contentsAsBytes() // An we now invoke the handler handler.handleRequest(event, context) } then: // We expect the PDF generator to be called. It means we were // able to correctly process the JSON from the downstream system 1 * pdfGenerator.generate(_) >> new byte[1] 1 * orderService.fetch(bucket, inputKey) >> mockS3Object 1 * orderService.save(bucket, outputKey, _) } }
该测试将预期消息设置为消息契约。然后,它通过AWS SDK调用来模拟S3事件以返回预期消息的消息有效负载。第三,它使用模拟事件调用lambda函数,然后验证调用的PDF和持久性服务。
运行此测试会导致使用我们预期的JSON格式生成Message Pact文件。这与前一篇文章中的消费者测试几乎相同(除了嘲笑AWS的东西)。但是,我们假装响应AWS事件,而不是测试从消息队列中消费消息。
旧版应用程序提供商
现在是重要的一部分。嗯,这一切都很重要。所以,现在更重要的部分。我们希望确保我们添加到遗留应用程序的代码位始终生成可由Lambda函数处理的JSON文件。我们可以通过使用我们用于消息提供程序的Message Pact验证来实现。我们创建了一个使用@PactVerifyProvider注释注释的测试方法,该注释与来自使用者测试的pact文件中的描述相匹配。此方法必须调用生成JSON数据的代码,该数据通常会写入S3存储桶并返回,以便可以根据我们的Lambda函数预期进行验证。
与大多数遗留应用程序一样,编写起来并不像我们嘲笑很多合作者来使其工作那么容易,我不会厌倦这些细节。以下是验证功能的简化版本:
class SubmittableSupplierOrderPact { @PactVerifyProvider('a purchase order in json format') String jsonForPurchaseOrder() { // This was the cause of our failure. A change in these classes // caused the generated JSON to change SupplierOrderView supplierOrder = supplierOrderViewFixture() ISupplierOrderItemView item1 = new SupplierOrderItemView() item1.with { setProductCode('1234') setProductDescription('Test Product 1') setPurchaseOrderQuantity(10) setListPrice(200) setTotalPriceExTax(100) } ISupplierOrderItemView item2 = new SupplierOrderItemView() item2.with { setProductCode('1235') setProductDescription('Test Product 2') setPurchaseOrderQuantity(50) setListPrice(200) setTotalPriceExTax(900) } List orderItems = [ item1, item2 ] IOrganisation organisation = [ getEmailAddress: { 'TestSupplier@wild-serverless-west.com' } ] as IOrganisation // The model class that gets rendered to JSON def subject = new SubmittableSupplierOrder(supplierOrder, orderItems, organisation, // yikes! timezones! SystemParameterManager.timeZoneId) // This is the Object mapper used to convert the model classes to JSON. Hopefully nobody // changes the actual code to use something else. But as it is a legacy application, it // is unlikely. def mapper = new JSONMapperModule().provideReportObjectMapper() // return the JSON representation mapper.writeValueAsString(subject) } }
运行Pact-JVM验证程序将导致调用函数jsonForPurchaseOrder,并根据pact文件中的消息有效内容验证结果。现在,如果从遗留应用程序生成的JSON发生变化,我们的Lambda函数无法处理它,我们将获得失败的构建。
对我们来说,这导致客户总是按照承诺获得他们的PDF,并且更快乐的交付经理。但我怀疑最后一点只是巧合。
看,马,我有一个合同测试锤!
既然我们已经对消息队列实现了合同测试,并且已经对Lambda函数调用实现了合同测试,我们就开始在我们可以使用这些异步合同测试的地方看到模式。我们还了解了Context Boundary作为进行合同测试的重要场所。
我们在一个有限的上下文中有一个服务,它创建了一个事件,需要将它传递给另一个有界上下文中的服务。您可以使用的模式是在边界上具有可以接受请求的适配器服务。但在我们的情况下,我们没有太多时间(第二个上下文中的大多数服务尚未存在),并且数据的所有权随着调用传递(数据现在由新服务拥有,只有参考存储到前一个上下文中的数据)。数据流也是此阶段的一种方式。
有人认为,通过合同测试,我们可以将JSON文档以正确的格式推送到文档存储。实质上,我们可以将文档存储视为传输机制,就像我们将S3存储桶视为一个一样。服务1A是提供者,JSON文档是消息有效负载,而另一方(服务2A)的服务是消费者。
综上所述
合同测试无服务器功能与我们之前完成的合同测试没有什么不同。他们在中间有输入,输出和东西,喜欢与常规功能(和孩子)一样行为不端。如果数据格式发生变化,任何异步调用(如响应事件而调用的Lambda函数)以及以非结构化格式(如JSON)传递的数据也可能容易失败。而且数据的格式也会发生变化。事实上,你的JSON格式可能已经改变了,你可能还没有注意到它。
与消息队列一样,当您需要更改消息格式时,知道谁正在消费您的消息以及消费它们的方式可能是一件幸事。与无服务器功能相同。知道哪些函数将响应您写入该S3存储桶的JSON文件,以便将来更容易更改该JSON文件。你将来必须改变它。或者你可能已经改变了它,你还没注意到它!
原文:https://dius.com.au/2018/10/01/contract-testing-serverless-and-asynchronous-applications-part-2/
本文:
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 24 次浏览
【合约测试】合同测试无服务器和异步应用程序
随着向微服务转移,或μ服务更时尚,使用Pact进行消费者驱动的合同测试,这是一种策略,可以确定我们所有的服务是否能够正确地相互通信。不要求我们所有的服务都相互通信。它还使我们能够确定任何服务的消费者是谁。这很有帮助,因为如果你知道你的消费者是谁,那么当你想破坏某些东西时,你就知道该和谁交谈。或者当他们破坏某些东西时
我们为基于HTTP的微服务做了这个。然后我们添加了一些消息队列和lambda函数。只是因为我们可以。
通过消息队列进行异步通信
我们开发的一些服务开始以异步方式通过消息队列进行通信。很明显,现在知道消息的消费者是谁更为重要。使用同步通信,如果出现故障,参与者是谁是明显的。使用邮件队列,您可能不知道谁正在使用您的邮件,或者是否由于邮件更改而导致任何失败。
我觉得,典型的态度是生成消息,将其扔到队列中,这不再是你的问题。看起来非常类似于我们尝试使用Restful API和微服务进行更改的想法。
我目睹了由于消息中格式错误的日期导致两个团队之间的服务系统故障。通过多次部署到QA环境,需要数天才能解决。
关于如何确保服务通过消息队列进行通信的问题没有受到格式错误的消息的影响,让我想到了联系测试。进行合同测试以确保消息生产者和消费者能够正确地进行通信似乎是正确的想法。但问题比基于HTTP的服务更复杂,我们可以在HTTP级别模拟事物。一切都讲HTTP。说到消息队列,根据使用的消息队列,协议会有所不同。而且我不想创建一个模拟ActiveMQ,RabbitMQ,SQS,Kafka和Kinesis服务器,仅举几例。
这导致认识到,为了验证合同,底层消息队列通常是无关紧要的。只要您可以确保消息生成器生成格式正确的消息,并且使用者能够使用它,您就不需要实际的消息队列。这让我很开心。
所以我创建了消息合约。
这与常规Pact测试的工作方式类似。 我们创建一个消费者测试,生成并发布一个pact文件,然后验证我们的消息提供者是否生成了正确的消息。
消费者测试
大多数消息队列使用者是使用回调机制实现的,通常是某种消息监听器,它通过与SDK库集成从消息队列接收消息。为了能够测试我的消费者,我将使用者分成两个类,一个与消息队列库集成的消息监听器,以及一个处理消息的消息处理程序。除了将消息传递给处理程序之外,消息侦听器不执行任何操作。通过这种方式,我可以只使用不需要消息队列的处理程序编写消费者合同测试。
消费者合同测试以类似的方式工作。我指定了我希望收到的消息,然后获得Pact测试框架以使用每条消息调用消息处理程序。到目前为止,这已经用于测试Kafka,SQS和Kinesis消息消费者。
下面是一个JVM消息处理程序的示例,它将处理来自Kafka主题的消息作为Spock测试。但是你应该能够使用任何测试框架,比如JUnit或TestNG。
第1步 - 定义消息期望
消费者测试从定义消息期望开始。基本上,我们正在设置我们希望收到的信息。我们使用PactMessageBuilder来设置协议和消息。
given: def messageStream = new PactMessageBuilder().call { serviceConsumer 'messageConsumer' hasPactWith 'messageProducer' given 'order with id 10000004 exists' expectsToReceive 'an order confirmation message' withMetaData(type: 'OrderConfirmed') // Can define any key-value pairs here withContent(contentType: 'application/json') { type 'OrderConfirmed' audit { userCode string('messageService') } origin string('message-service') referenceId regexp('\\d+\\-\\d', '10000004-2') timeSent timestamp value { orderId regexp('\\d+', '10000004') value decimal(10.00) fee decimal(10.00) gst decimal(15.00) } } }
第2步 - 使用生成的消息调用消息处理程序
此示例测试从Kafka主题获取消息的消息处理程序。 在这种情况下,Pact消息被包装为Kafka MessageAndMetadata类。
when: messageStream.run { Message message -> messageHandler.handleMessage(new MessageAndMetadata('topic', 1, new kafka.message.Message(message.contentsAsBytes()), 0, null, valueDecoder)) }
类似地,对于处理程序从SQS接收消息的示例,该消息是由像Jackson这样的库反序列化的对象,您可以执行以下操作:
when: messageStream.run { Message message -> def order = objectMapper.readValue(message.contentsAsBytes(), Order) assert messageHandler.handleMessage(order) != null }
这里的objectMapper是Jackson库中的ObjectMapper。 以与收到实际消息时相同的方式对消息进行反序列化非常重要。
第3步 - 验证消息是否已正确处理
我们的处理程序应该接收消息并将订单详细信息保存到我们的订单存储库中,因此我们可以检查它是否正常工作。
then: def order = orderRepository.getOrder('10000004') assert order.status == 'confirmed' assert order.value == 10.0
Pact在这里没有做任何事情,它只是将DSL的期望转换为JSON文档,并将其传递给一些要执行的代码。实质上,它假装是一个消息队列。如果一切都通过,则生成pact文件。这是重要的一点,因为我们现在可以发布它。
验证我们的消息提供商
关闭循环的下一步是验证提供程序服务是否正确生成消息。我们通过让Pact以与消费者测试相反的方式工作来实现这一目标。同样,Pact将伪装成消息队列并让消息提供者向其发送消息。这将与已发布的pact文件进行匹配。
我们通过从消息生成代码中分割消息发送代码来实现此目的。这样,负责将消息放入消息队列的类委托给另一个类来生成实际消息。然后我们可以调用后一类在验证测试期间生成一条消息,以确定它是否正确生成消息。唯一需要注意的是,以这种方式测试的类必须是实际用于生成真实消息的类。
Pact-JVM使用Java注释来查找可以调用消息生成器并返回生成的消息的测试类。如果您使用的是JUnit,则可以使用AmqpTarget来驱动此行为,而不是用于常规pact验证测试的HttpTarget。另请参阅在Gradle中验证消息提供程序和在Maven中验证消息提供程序,以获取有关如何在这些工具中启用此功能的信息。
现在,当我们验证消息pact文件时,Pact-JVM将在测试类路径中查找使用@PactVerifyProvider注释的方法,这些方法与pact文件中的内容具有匹配的描述。在我们之前的示例中,它是订单确认消息。
因此,这是一个验证来自先前的消费者测试的消息的示例。
class ConfirmationKafkaMessageBuilderTest { @PactVerifyProvider('an order confirmation message') String verifyMessageForOrder() { Order order = new Order() order.setId(10000004) order.setExchange('ASX') order.setSecurityCode('CBA') order.setPrice(BigDecimal.TEN) order.setUnits(15) order.setGst(15.0) order.setFees(BigDecimal.TEN) def message = new ConfirmationKafkaMessageBuilder() .withOrder(order) .build() JsonOutput.toJson(message) } }
在这种情况下,ConfirmationKafkaMessageBuilder是用于生成发送到Kafka主题的消息的类。但是这可以用于任何消息队列,因为我们没有使用任何特定的Kafka。 Pact-JVM现在将调用verifyMessageForOrder方法并验证返回的内容是否与pact文件中的消息内容匹配。
综上所述
我们可以使用联系测试之类的策略来验证通过消息队列进行通信的使用者和提供者是否可以工作而无需实际运行的消息队列。我们通过以下步骤执行此操作:
- 将消息使用者拆分为特定于队列的消息处理程序和处理该消息的类。
- 编写一个调用消息处理类的消费者测试。
- 发布生成的pact文件。
- 将我们的消息提供程序拆分为特定于队列的发布者和消息生成器
- 设置我们的验证(使用Pact-JVM)来调用使用@PactVerifyProvider注释的测试类的方法
- 获取带注释的测试方法以从消息生成器返回消息JSON。
现在我们可以在部署之前捕获这些日期格式问题。
在本博客的第二部分中,我将向您展示如何使用相同的技术来验证与AWS lambda函数的合同。
原文:https://dius.com.au/2017/09/22/contract-testing-serverless-and-asynchronous-applications/
本文:
讨论:请加入只是星球或者小红圈【首席架构师圈】
- 13 次浏览
【敏捷测试】敏捷方法论:理解敏捷测试的完整指南
在过去几年中,一种创建软件的新方式已经风靡软件开发和测试世界:敏捷。
事实上,根据VersionOne的敏捷状态报告,截至2018年,97%的组织以某种形式实践敏捷。 然而,受访者表示,这种采用在其组织中并不总是很普遍,这意味着在采用和成熟方面还有很长的路要走。
那么究竟什么是敏捷的,为什么它如此迅速地变得如此受欢迎? 让我们更详细地探索敏捷方法所涉及的内容以及如何在组织中引入它。 具体来说,我们将涵盖:
- 测试如何适应敏捷方法?
- 在敏捷团队上测试的不同方法有哪些?
- 敏捷运动的下一步是什么?
关于敏捷方法论
敏捷方法已经风靡软件开发世界并迅速巩固其作为“黄金标准”的地位。敏捷方法论都是基于敏捷宣言中概述的四个核心原则开始的。这些方法植根于适应性规划,早期交付和持续改进,所有这些都着眼于能够快速,轻松地响应变化。因此,在VersionOne的2017年敏捷状态报告中,88%的受访者认为“适应变化的能力”是拥抱敏捷的头号优势,这一点也就不足为奇了。
然而,随着越来越多的开发团队采用敏捷理念,测试人员一直在努力跟上步伐。这是因为敏捷的广泛采用促使团队更频繁地发布版本和完全无证的软件。这种频率迫使测试人员在进行测试时,他们如何与开发人员和BA一起工作,甚至他们进行的测试,同时保持质量标准。
对敏捷团队进行测试意味着什么?
敏捷原则都是关于协作,灵活和适应性的。它建立在现在世界变化的前提下,这意味着软件团队不再需要多年才能将新产品推向市场。在那段时间内,竞争对手的产品或客户期望可能会发生变化,而团队的风险则无关紧要。敏捷通过适应团队成功所需的内容,帮助团队更多地协作,从而最大限度地降低风险。它通过鼓励团队定期展示他们的工作并收集反馈以便他们能够快速适应变化来实现这一目标。
快速启动您的敏捷协作:阅读我们的文章“开发人员和测试人员之间保持一致的秘密”。
缩小测试范围,敏捷开发的快节奏为测试人员带来了几个必要条件:
- 根据风险确定需求的优先级,因为无法测试所有内容
- 自动化测试以提高效率
- 增加探索性测试的使用,以加快从代码交付到测试完成的时间,并强调创建有效代码的必要性
- 适应从冲刺到冲刺的变化
第四个必要条件 - 适应性 - 特别重要,因为它要求测试人员具有更广泛的跨功能测试技能,这代表了与瀑布环境中经常需要的较窄测试技能的背离。此外,与瀑布环境不同,遵循敏捷方法的测试人员需要与开发人员保持密切联系,以便在整个软件开发生命周期中协作进行测试。在瀑布式方法中,通常会有一个大型的需求文档供测试人员测试。该文档不会经常更改,因此测试人员可以相当独立于开发人员而存在。但是,大多数敏捷方法对文档都很清楚,新功能的要求可能只在需求跟踪系统中的票证中,而没有列出所有边缘情况。这些场景中的测试人员需要与开发和业务团队进行高度沟通,因为几周前他们编写的测试可能很快就会过时。为了取得成功,测试人员需要灵活并能够适应移动目标。
为了取得成功,测试人员需要灵活并能够适应移动目标。
一般而言,敏捷宣言有四个核心原则,对于测试人员来说很重要:
- 个人和流程与工具之间的互动
- 通过综合文档工作软件
- 响应遵循计划的变更
- 通过合同谈判与客户合作
所有这一切的底线是,每个人 - 测试人员,开发人员和其他人 - 必须发展才能拥抱敏捷的工作方式。
敏捷不是放之四海而皆准的
每个组织都是独一无二的,面临着不同的内部因素(即组织规模和利益相关者)和外部因素(即客户和法规)。 为了帮助满足不同组织的不同需求,您可以在其中一种敏捷方法中使用各种敏捷方法和几种不同类型的测试。 哪种组合适合您的团队取决于您的内部和外部因素,需求和目标。 让我们来看看一些最流行的敏捷方法和测试方法,包括:
敏捷方法论
- Scrum
- 看板
测试方法
-
行为驱动开发(BDD)
-
验收测试驱动开发(ATDD)
-
探索性测试
-
基于会话的测试
2敏捷方法论类型
1)Scrum
它是什么?作为最受欢迎的软件测试方法之一(58%的组织已根据VersionOne采用了敏捷方法),Scrum采用高度迭代的方法,专注于在每个sprint之前定义关键特性和目标。它旨在降低风险,同时快速提供价值。
Scrum从一个需求或用户故事开始,概述了功能应该如何执行和测试。然后,该团队通过一系列冲刺循环,以快速提供小规模的价值爆发。为了帮助团队以这种灵活的方式工作并避免改变优先级,Scrum要求从一开始就回答问题。
它和瀑布有什么不同?瀑布包括在发布产品之前的几个测试和错误修复周期,而Scrum更具协作性和迭代性。其中一个最大的区别是瀑布早期需要大量文档。这个文档使得在过程继续进行时更改功能变得更加困难,这在某些环境(例如消费级软件)中可能是负面的,而在其他环境中则是积极的(例如团队试图发射火箭的那些)没有人想要经常危险移动的要求)。也就是说,您可能会认为Scrum就像许多“迷你瀑布”一样,因为每个冲刺开始时需求都很明确,不应该在其中移动。不同之处在于,下一个冲刺的详细要求不是提前几个月设定的。
潜水更深入,Scrum要求测试人员,开发人员和BA之间进行更多定期协作,通常采用每日站立和冲刺回顾的形式,以确保正确的沟通和协调。此外,还有一位Scrum Master通过删除团队中的阻截者来确保他们最有效,从而帮助项目完成任务。 Scrum Master可以是团队中的任何人,例如开发人员或测试人员。
采用有什么意义? Scrum为来自瀑布环境的团队提供了最简单的转换之一,因为它基于时间的冲刺和发布仍然可以提前计划。也就是说,它确实需要更快的迭代和更强的协作。
它是谁的?由于其快速迭代,Scrum最适合那些客户和利益相关者希望通过在展示会议上定期查看工作产品而积极参与的团队。此协作允许团队对即将到来的陈列柜进行更改。在采用Scrum方法时应该参与的主要团队成员包括:
- 产品拥有者
- Scrum Master
- 开发商
- 自动化工程师
- 测试者
- 利益相关者
什么是最佳做法?除了强大的沟通,协作和适应性之外,遵循Scrum方法的测试人员的其他最佳实践还包括:
- 根据销售代表或客户的通信(通常以用户故事的形式)确定验收标准(注意:此直接连接应有助于减少误传)
- 使用验收标准开发代码并确保团队批准该代码
- 在将其部署到生产环境之前,在类似沙箱的环境以及类似生产的环境中测试代码
2)看板
它是什么?看板是一种非常简单的基于敏捷的方法,植根于制造业(它由丰田公司开发,旨在帮助提高工厂的生产率)。在它的核心,看板可以被认为是一个大的,优先的待办事项列表。与Scrum一样,看板中的需求由其当前阶段(待办,开发,测试,完成)跟踪。
与Scrum不同,看板不是基于时间的。相反,它完全基于优先权。当开发人员准备好完成下一个任务时,他/她将其从待办事项列表中拉出来。由于计划会议较少,这种方法意味着团队需要非常接近。在这种类型的环境中,如果开发人员的工作速度比测试人员快得多,那么就会出现瓶颈。在这些情况下,团队中的任何人都应该跳进并帮助不同的领域。当然,满足这种需求需要很大的灵活性和适应性。
它和瀑布有什么不同?看板仍然有像瀑布这样的要求,但是由于测试团队没有开始考虑测试每个要求,直到开发人员从积压的顶部选择它,因此需求可能会发生变化。相比之下,瀑布是基于时间的,在计划中有很多开销。在某些情况下,在瀑布环境中进行繁重的规划是很好的,例如在建造昂贵的东西时,但并不总是必要的。使用看板,版本仍然有计划,但团队通常不会在某些日期向任何人提供功能,除非相关项目位于待办事项的顶部。
采用有什么意义?看板为正确的团队提供简单的过渡。为了顺利过渡到看板,业务分析师,开发人员,测试人员和利益相关者应该坐在一起并定期沟通。转换到看板时,重要的是要记住这种方法提供了将代码投入生产的最快方法,但代码可能会有一些技术债务。这是因为开发时并不总是知道接下来的内容并不一定能够生成最可重用的代码。
它是谁的?看板最适合不为公众制作功能和/或承诺发布某些日期的小型团队或团队。此外,它是主要专注于维护工作的任何产品或团队的首选方法选择,因为错误并不总是直截了当,往往需要研究解决,这使得时间管理具有挑战性。根据Scrum或Waterfall方法,不能最小化问题规划量的团队可能会更好。
应参与看板环境的主要团队成员包括:
- 产品拥有者
- 专案经理
- 开发商
- 自动化工程师
- 测试者
什么是最佳做法?除了保持可见性和优先协作之外,遵循看板方法的测试人员的最佳实践还包括:
- 在业务所有者,开发人员和测试人员之间保持非常开放的沟通渠道
- 确保团队可以灵活地承担其核心职责之外的其他角色,以帮助消除瓶颈
- 让每个人都成为产品的所有者,以便他们完全关注结果
4敏捷测试方法
1)行为驱动开发(BDD)
它是什么?很多人都听说过或使用过测试驱动开发(TDD)。例如,开发人员在编写代码之前使用TDD编写单元测试失败。 BDD基于与TDD相同的原则,但它不是单元测试,而是要求在业务级别进行更高级别的测试。 BDD不是像TDD那样从面向技术的单元测试开始,而是从基于最终用户行为的初始需求开始,并且需要“人类可读”的测试,甚至可以替换一些需求文档。此要求基于产品应展示的行为,为工程师在开发测试时使用创建气密指南。
有关更多信息,请阅读我们的文章:“为什么BDD是DevOps中的测试秘诀。”
具体来说,BDD使用Gherkin Given / When / Then语法从功能规范开始。然后,该规范指导跨功能的开发人员,测试人员和产品所有者。正如他们所做的那样,他们使用自动化测试功能来确定完整性,改进代码直到通过测试,就像TDD方法一样,除了团队级别。为了确保测试通过(并且通常需要多次尝试),开发人员应该只重构代码,而不是添加任何新功能。
总而言之,BDD需要一种“智能”自动化策略,以提高效率。该策略将BDD与其他敏捷方法区分开来。
它与标准瀑布测试有何不同? BDD与标准的瀑布测试极为不同,因为前者要求在需求的早期编写测试用例,并要求在开发周期结束时执行这些测试。但是,在敏捷环境中使用BDD,测试不是基于需求,测试是在功能开发的情况下进行的。
此外,在Waterfall方法中,测试人员是编写测试用例的人。另一方面,BDD方法适用于编写测试的企业主。此开关可减少业务分析人员,开发人员和测试人员之间的通信(或沟通错误)。
采用有什么意义?当团队习惯于传统的测试方式时,更改为BDD方法可能具有挑战性。它需要BA或测试人员预先编写测试,并且开发人员要在代码中编写测试规范以进行匹配。这是团队内部的一种新型协调方式,但非常积极的是团队合作为一个单元,包括业务用户。
它是谁的? BDD方法非常适合从事以功能为中心的软件和/或将用户体验放在首位的团队的团队。应参与BDD环境的主要团队成员包括:
- 产品负责人/业务分析师
- 专案经理
- 开发商
- 自动化工程师/测试员
什么是最佳做法?遵循BDD方法的测试人员的最佳实践包括:
- 简化文档以保持整个流程的精益
- 采用“三友”模式,产品所有者,开发人员和测试人员组成一个有凝聚力的团队
- 使用像Cucumber这样的测试框架来定义标准
- 以尽可能容易重用的方式构建自动化测试
- 让业务分析师学习Gherkin语法并直接编写测试用例
2)验收测试驱动开发(ATDD)
它是什么? ATDD就像BDD一样,它要求首先创建测试,并要求编写代码以通过这些测试。然而,与TDD中的测试通常是面向技术的单元测试不同,在ATDD中,测试通常是面向客户的验收测试。
ATDD背后的想法是用户对产品的感知与功能同样重要,因此这种感知应该推动产品性能,以帮助提高采用率。为了实现这一想法,ATDD收集客户的意见,使用该输入来制定验收标准,将该标准转换为手动或自动验收测试,然后根据这些测试开发代码。与TDD和BDD一样,ATDD是测试优先的方法,而不是需求驱动的过程。
与TDD和BDD方法一样,ATDD通过消除开发人员解释产品使用方式的需要,帮助消除潜在的误解区域。 ATDD比TDD和BDD更进一步,因为它直接进入源(也就是客户)以了解产品的使用方式。理想情况下,这种直接连接应有助于最大限度地减少在新版本中重新设计功能的需要。
它与标准瀑布测试有何不同? ATDD与标准瀑布测试不同,因为它是测试优先方法。标准瀑布测试要求根据需求预先编写测试用例,而ATDD不是需求驱动的测试过程。
采用有什么意义?因为ATDD代表了与传统方法的背离,所以从一个到另一个并不容易让团队去做。为了处于采用ATDD方法的最佳位置,团队需要获得利益相关者的支持,这有时会证明是有挑战性的。
它是谁的?由于强调用户感知,ATDD最适合专注于用户体验的团队,具有高采用率的目标,并希望在未来版本中尽量减少功能更改的数量。应参与ATDD环境的主要团队成员包括:
- 客户/客户代言人
- 开发人员
- 产品负责人/业务分析师
- 自动化工程师/测试员
- 专案经理
什么是最佳做法?遵循ATDD敏捷方法的测试人员的最佳做法包括:
- 与客户密切互动,例如通过焦点小组,以确定期望
- 倾向于面向客户的团队成员,如销售代表,客户服务代理和客户经理,以了解客户的期望
- 根据客户期望制定验收标准
- 优先考虑两个问题:
如果是X,客户会使用该系统吗?
我们如何验证系统是否支持X?
3)探索性测试
它是什么?接下来我们进行探索性测试,这实际上是一种功能测试,但在敏捷环境中非常重要。探索性测试使测试人员对代码拥有所有权,以有组织,混乱的方式对其进行测试。在这种情况下,测试人员不会遵循测试步骤,而是以标准或巧妙的方式使用软件来尝试打破它。测试人员将像往常一样记录缺陷,但并不总是提供有关应用程序测试内容和方式的详细文档。
探索性测试不是脚本化的。相反,它是基于每个独特的软件开发最佳测试。由于其无脚本方法,探索性测试通常模仿用户在现实生活中如何与软件交互。
总体而言,探索性测试遵循以下四个关键原则:
- 并行测试计划,测试设计和测试执行
- 具体而灵活
- 协调调查潜在的机会
- 知识共享
它与标准瀑布测试有何不同?探索性测试实际上可以在Waterfall和Agile环境中完成,但是敏捷环境中测试人员和开发人员之间的紧密集成有助于缓解在瀑布环境中运行探索性测试时可能出现的任何瓶颈。
此外,为了在Waterfall环境中运行探索性测试,必须提供有关测试结果的文档,并且该文档应该易于追溯到需求。当然,这种类型的文档在任何环境中都是有用的。
采用有什么意义?拥抱探索性测试相对容易,因为它可以快速启动(和扩展),简单易学并为整个团队带来好处。也就是说,重要的是要记住,它不应该是唯一的测试形式(相反,它应该告知接下来会发生什么类型的测试)。此外,即使它没有脚本,探索性测试也不应该是非结构化的(测试人员仍然需要设置目标,记录您的活动并采取特定用户角色的思维模式)。
它是谁的?探索性测试有助于减少测试时间,发现更多缺陷并提高代码覆盖率。因此,探索性测试最适合受时间限制的团队,需要帮助确定要运行的最佳测试类型的团队(特别是在没有开发人员规范的情况下)以及希望确保他们没有的团队以前的测试都不会错过任何东西。应参与探索性测试的主要团队成员包括:
- 测试人员(虽然团队中的每个人都应该以某种方式参与)
什么是最佳做法?使用探索性测试的测试人员的最佳实践包括:
- 使用Mindmap或电子表格等组织应用程序中的功能
- 专注于某些领域或某些场景
- 跟踪经过测试的内容,以帮助重现任何错误
- 在qTest Explorer之类的工具中记录结果,因此对测试的内容有一定的责任感
4)基于会话的测试
它是什么?最后,让我们回顾一下基于会话的测试。基于会话的测试建立在探索性测试的基础上,提供更多结构因为探索性测试完全没有脚本,所以它使问责制变得困难,并且在很大程度上依赖于所涉及的测试人员的技能和经验。基于会话的测试旨在通过为探索性测试带来更多结构来缓解这些缺点,而不会剥夺探索性测试提供的好处,例如更好地模仿用户体验和通过测试获得创造性的能力。
基于会话的测试通过在时间限制的,不间断的会话期间进行测试,针对章程进行测试并要求测试人员报告每个会话期间发生的测试来提供此结构。此外,基于会话的测试应该通过测试人员和管理人员之间的“汇报”进行限制,其中包括五个PROOF点:发生了什么(过去),取得了什么(结果),阻碍了什么(障碍) ),还有什么需要做的(Outlook)以及测试人员对此的感受(感受)。
它与标准瀑布测试有何不同?与探索性测试相同,基于会话的测试可以在Agile和Waterfall环境中运行,但它更有利于敏捷环境中常见的测试人员和开发人员之间的紧密协作。
采用有什么意义?与探索性测试非常相似,采用基于会话的测试证明相对容易,因为它易于快速启动和启动。对于已经习惯于探索性测试的测试人员来说,最大的障碍是采用基于会话的测试调用的附加结构。与探索性测试一样,运行基于会话的测试的团队应该记住它不是最后一站,而是一种帮助确定下一步要进行的最佳测试类型的方法。
它是谁的?基于会话的测试有助于缩短测试时间,同时增加缺陷发现和代码覆盖率,使其成为面临时间限制并需要更多指导以确定要运行的测试类型的团队的理想选择。对于在探索性测试中获益但需要在整个过程中改进问责制的团队而言,它也是理想的选择。应参与基于会话的测试的主要团队成员包括:
- 测试者
- 经理
什么是最佳做法?使用基于会话的测试的测试人员的最佳实践包括:
- 概述任务,以便测试人员清楚他们正在测试的软件
- 开发一个明确的章程,指明任务,要测试的软件区域,运行会话的测试人员,会话将在何时进行,以及设计和执行的测试,发现的错误和整体说明(与探索性测试一样,像qTest Explorer这样的文档工具可以在这里提供帮助)
- 在没有任何中断的情况下运行测试会话
- 在会议报告中明确记录会议期间的活动和说明
- 在测试人员和经理之间进行汇报,以审查会议的结果并讨论下一步的测试步骤
如何使测试与敏捷交付流程保持一致
一旦确定哪种测试方法适合您的组织,您就还没有完成。您仍需要将测试与交付一致。为实现这一目标,我们建议采用三管齐下的方法:
1)尽早参与开发过程
测试人员越早参与,越好。理想情况下,测试人员应该从第一天起就在场。这是因为让测试人员在桌面上的每一步都能提供更高水平的需求和目标洞察力,鼓励合作并帮助确定频繁(如果不是连续)测试的必要性。
2)经常测试,但是很周到
随着越来越多的团队采用敏捷方法,效率就是一切。这种对速度的需求促使团队采用DevOps和持续集成以保持移动,这需要更频繁地进行测试。但是在效率和频率集中的重组中,测试人员需要保持周到,以免产生更多开销并运行不必要的测试,这实际上会减慢过程。
3)通过测试创建来运行
牢记在当今敏捷,DevOps驱动的世界中对速度的需求,测试人员需要在创建测试时立即投入运行。具体来说,越多的测试人员可以减少从需求收集到测试创建的时间越多越好。从一开始就在所有谈话中坐下来应该有助于这方面。
敏捷测试的下一步是什么?
虽然敏捷已经在软件开发生命周期中取得了重大进展,但仍有很长的路要走,特别是在测试团队中。
展望未来,更广泛的采用和更加成熟的敏捷方法将要求测试人员超越测试创建和执行,并开始专注于代码交付和集成。与此同时,测试人员需要磨练自己的自动化技能,更多地参与整个软件开发过程,并继续与开发人员建立协作关系。最终,这些变化还将要求测试人员成为开发和产品使用方面的专家,以便提供更全面的测试策略并承担“质量冠军”的角色。
将来,对于在敏捷环境中工作的测试人员来说,三个关键原则将变得尤为重要:
1)沟通
敏捷需要测试人员和开发人员之间的紧密协作,而这种协作使通信成为测试人员的首要任务。此外,在质量成为每个人的责任的世界中,测试人员将成为内部专家的“质量冠军”,这将使他们能够在聚光灯下清晰地传达测试需求和推理。
2)技能多样性
在敏捷环境中,一切都可以改变,这需要测试人员适应。这种适应性的一部分是拥有多样化的技能组合,以便测试人员可以根据需要改变方向。例如,功能测试人员需要将他们的技能扩展到手动脚本执行之外。这种多样化的技能组合是必须的,因为不同的冲刺需要在短时间内执行不同类型的测试。
3)商业心态
最后,Agile采用以客户为中心的方法,以确保客户尽可能快地尽早获得尽可能多的价值。测试人员在提供这一价值方面发挥着重要作用,但它需要他们采取商业思维方式,以便他们能够理解客户的期望,愿望和关注,并相应地制定他们的测试策略。
为什么领先的公司正在通过敏捷测试实现敏捷
超过300家领先的公司选择改进他们的软件测试流程,并通过采用敏捷。以下是其中一些领导者为什么选择使用qTest而说的原因:
“我们能够快速将所有测试案例从惠普质量中心缓解到qTest,并在短短几周内启动并运行团队。实施过程非常好“
-Radka Iordanova,Office Depot,Inc。电子商务总监
“当你转向敏捷时,仅仅改变你的开发方法还不够,你必须升级你的软件工具...... QASymphony正是我们所寻找的。”
-Alex Bantz,Salesforce Marketing Cloud质量工程总监
“我们已经看到了测试者错误的大幅减少,现在我们已经有了缺陷的历史。我们可以看到问题所在。 American Equity和QASymphony之间的合作非常精彩。“
-Dennis Young,美国股票QA助理副总裁
“我们评估了很多其他测试平台,发现qTest是最好的,而且到目前为止最直观......自首次实施qTest以来,我们的效率提高了至少50%。”
-Jesse Reynosa,Zappos高级质量工程师
特别感谢Ali Huffstetler为这个博客绘制图像。
原文: https://www.qasymphony.com/blog/agile-methodology-guide-agile-testing/ ,
- 361 次浏览
【软件开发】TDD,救世主还是噩梦?
测试驱动开发是一种编程方法,其中在编码之前创建测试。 下面,我列出了使其应用程序有用的一些原因。
- 1.测试可以作为代码的蓝图:在建造房屋之前,制定蓝图来帮助房屋建造者。 构建测试可帮助您了解应用程序的工作原理。 此外,它可以帮助您创建更优化的代码。
- 2.帮助开发者了解客户需求。
- 3. 可维护的代码,有利于团队合作,帮助未来的开发者。
- 4. 预防性,不仅仅是纠正性:构建测试可以让开发人员更加意识到可能发生的错误和边缘情况。
TDD 的三个阶段
TDD 的三个核心步骤:创建测试——实现代码——重构
1. 创建测试
此阶段将在提交消息中以“[RED]”开头。测试脚本需要精确但简单且可重用。例如,当您有一个按钮时,您可以检查它们在被单击后是否重定向到正确的路径。如果稍后您添加另一个,您可以重复使用它们。从这一步开始,您决定要实现的特定功能。使其具体而小。
然后,想象一下这个功能是如何工作的,可能的边缘情况是什么,将使用哪些组件,以及在制作测试脚本时它们将如何相互交互。您不必首先实现全部功能。测试一个小功能——实现——并迭代。
2. 实施代码
此阶段将在提交消息中以“[GREEN]”开头。对你来说可能是最令人兴奋的部分😜。开发人员将根据书面场景对功能进行编码。目的是从测试中消除当前的错误。
3.重构
此阶段将在提交消息中以“[REFACTOR]”开头。 在这个阶段,开发人员通过删除冗余而不改变程序的行为来优化他们的代码。
功能测试的类型
- 单元测试:检查最小的单元,如函数或方法,以使其正常工作。 自动化便宜。
- 集成测试:检查所有使用的模块是否可以很好地协同工作。 示例:对数据库的 API 调用。
- 验收测试:在发布前测试端到端产品。
..还有很多。 那么,您是否仍然怀疑最初的努力是否值得花时间? 事实上,测试并不是一个简单的概念。 你需要大量的练习才能获得最大的好处。 由于 TDD 起初可能看起来令人生畏,因此以下心态可以帮助您开始。
- 从一个小功能开始。
- 如果您从事单个项目,请对功能的流程充满想象力。 如果您与 PM 和其他用户一起工作,请有效地验证产品规格。
在行业中,测试的角色可以分配给软件工程师、QA 工程师或 SDET(测试中的软件开发人员)。 这取决于公司的政策。
我如何在我的项目中实现 TDD
上面是一个用 Jest 编写的典型前端单元测试的例子。 我创建了一个测试来检查操作员注册页面是否正确呈现(第 52-65 行)。 语法如下,
expect(/*get the component/).TestingFunction()
— 断言测试是否按照我们想要的方式运行。
A. 红色的
使用旧的提交消息约定,我首先为即将推出的功能创建了失败测试。 下面,我创建了两个测试来检查 1) 运营商注册页面是否正确呈现,以及 2) 当正确的用户通过身份验证时,运营商主页是否会正确呈现。 管道将失败,因为我还没有实现该功能。
b. 绿色
- 24 次浏览
【软件测试】Java消费者驱动的合同测试
Java中的Pact-JVM和Gradle
介绍
在这篇文章中,我们将在Gradle Spring Boot虚拟提供程序(RESTful Web Service)和Gradle虚拟使用者之间编写一个Consumer Driven Contract Test。
我们将使用Pact-JVM,它将为消费者项目提供模拟服务以生成Pact,并为提供者项目验证能力以验证Pact。
安装
Gradle
Gradle Wrapper允许任何人在不必安装Gradle的情况下处理您的项目。它确保构建的正确版本的Gradle作为此项目存储库的一部分提供。首先克隆包含虚拟提供者和虚拟消费者的样本库:
bash-3.2$ git clone https://github.com/the-creative-tester/consumer-driven-contract-testing-example.git Cloning into 'consumer-driven-contract-testing-example'...
remote: Counting objects: 47, done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 47 (delta 2), reused 42 (delta 1), pack-reused 0 Unpacking objects: 100% (47/47), done.
Checking connectivity... done.
提供者设置
导航到提供程序目录,您将在其中看到通过本指南使用Sprint Boot和Gradle构建的示例RESTful Web Service。尝试使用以下命令运行该服务:
bash-3.2$ ./gradlew clean build && java -jar build/libs/gs-actuator-service-0.1.0.jar
.. 2016-07-03 14:49:59.367 INFO 32114 --- [ main] hello.HelloWorldConfiguration : Started HelloWorldConfiguration in 6.782 seconds (JVM running for 7.452)
您现在应该能够通过导航到http:// localhost:8080 / hello-world或使用curl来达到服务(观察每次向服务发出请求时id增加):
bash-3.2$ curl http://localhost:8080/hello-world {"id":2,"content":"Hello World!"}
消费者设置
从消费者的角度来看,总是要生成契约。这一代可以分为三个部分。
第1部分:契约规则
在这一部分中,我们定义了一个模拟服务器的主机和端口来表示提供者:
@Rule
public PactRule rule = new PactRule(Configuration.MOCK_HOST, Configuration.MOCK_HOST_PORT, this);
private DslPart helloWorldResults;
第2部分:契约片段
在这一部分中,我们构建了一个Pact Fragment,它定义了一个提供者的预期契约:
@Pact(state = "HELLO WORLD", provider = Configuration.DUMMY_PROVIDER, consumer = Configuration.DUMMY_CONSUMER)
public PactFragment createFragment(ConsumerPactBuilder.PactDslWithProvider.PactDslWithState builder)
{
helloWorldResults = new PactDslJsonBody()
.id()
.stringType("content")
.asBody();
return builder
.uponReceiving("get hello world response")
.path("/hello-world")
.method("GET")
.willRespondWith()
.status(200)
.headers(Configuration.getHeaders())
.body(helloWorldResults)
.toFragment();
}
第3部分:契约验证
在这一部分中,我们确保第2部分中构造的片段与模拟服务器的响应匹配:
@Test
@PactVerification("HELLO WORLD")
public void shouldGetHelloWorld() throws IOException
{
DummyConsumer restClient = new DummyConsumer(Configuration.SERVICE_URL);
assertEquals(helloWorldResults.toString(), restClient.getHelloWorld());
}
尝试使用消费者目录中的Gradle生成Pact:
bash-3.2$ ./gradlew test
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:testBUILD SUCCESSFUL
Total time: 10.67 secs
然后将生成Pact并将其存储在pacts目录中,但它看起来像这样:
{
"provider" : {
"name" : "dummy-provider"
},
"consumer" : {
"name" : "dummy-consumer"
},
"interactions" : [ {
"providerState" : "HELLO WORLD",
"description" : "get hello world response",
"request" : {
"method" : "GET",
"path" : "/hello-world"
},
"response" : {
"status" : 200,
"headers" : {
"Content-Type" : "application/json;charset=UTF-8"
},
"body" : {
"id" : 5677679801,
"content" : "dugNvVPasiFRnzqpPNuq"
},
"responseMatchingRules" : {
"$.body.id" : {
"match" : "type"
},
"$.body.content" : {
"match" : "type"
}
}
}
} ],
"metadata" : {
"pact-specification" : {
"version" : "2.0.0"
},
"pact-jvm" : {
"version" : "2.1.12"
}
}
}
提供者
现在,Pact已由Consumer生成,并假设Provider(RESTful Web Service)正在运行。您可以从提供程序目录运行以下命令,以确保提供程序满足Consumer的所有期望:
bash-3.2$ ./gradlew pactVerify
:pactVerify_dummyProviderVerifying a pact between dummy-consumer and dummyProvider
[Using file /Users/jasonthye/Dev/pact-example-gradle/pacts/dummy-consumer-dummy-provider.json]
Given HELLO WORLD
WARNING: State Change ignored as there is no stateChange URL
get hello world response
returns a response which
has status code 200 (OK)
includes headers
"Content-Type" with value "application/json;charset=UTF-8" (OK)
has a matching body (OK)
:pactVerifyBUILD SUCCESSFUL
Total time: 9.936 secs
完整的例子
https://github.com/the-creative-tester/consumer-driven-contract-testing-example
- 35 次浏览
【软件测试】ducktape :分布式系统集成与性能测试库
Ducktape包含用于运行系统集成和性能测试的工具。 它提供以下功能:
- 以简单的单元测试样式编写分布式系统的测试
- 默认情况下隔离,因此系统测试尽可能可靠。
- 用于在不同环境中集群提升和拆除服务的实用程序(例如本地,自定义集群,Vagrant,K8s,Mesos,Docker,云提供商等)
- 触发特殊事件(例如弹出服务)
- 收集结果(例如日志,控制台输出)
- 报告结果(例如满足预期条件,绩效结果等)
- 51 次浏览
【软件测试】企业环境中的验收测试
画景观
在专注于任何功能测试自动化技术和工具之前,先看大局总是一个好主意。 这里有一些值得强调的点。
遵循正确的模式
众所周知,在设计自动化测试和持续集成管道时,应该遵循测试金字塔概念(而不是测试冰淇淋蛋卷)。
这背后的原因很简单——金字塔底层的测试执行得更快,而且实施起来通常更便宜。此外——我们越早发现错误——越好。这并不意味着自动化更高级别的测试(验证所有系统组件)不那么重要。
保持平衡
决定哪些测试应该自动化以及自动化程度如何始终是测试策略的关键部分。遵循测试金字塔是一个很好的起点,但同样重要的是不要低估其他测试技术的价值,包括功能性(例如探索性)和非功能性(代码分析、性能、弹性、安全性……)。在自动化功能测试时,根据经验,用户界面测试应保持在最低限度(涵盖关键业务路径),并尽可能地通过 API 进行测试。
选择你的工具
单元和集成测试的工具选择与开发组件的技术密切相关。 JUnit、Mockito、Jest 等工具可帮助开发人员在早期构建阶段实现测试覆盖。
我们可以在测试金字塔的更高层次上开始思考常见的测试框架。由 Spring Cloud Contract 和 PACT 等工具支持的 Consumer Driven Contracts 作为早期非功能性 API 合同验证的手段越来越受欢迎。
但是,如何在多个组件和服务协同工作的集成环境中验证对我们的业务至关重要的逻辑呢?我们如何组织我们的测试场景并通过合理的努力使它们可执行?
这就是端到端测试框架可能派上用场的地方!
那里有很多商业框架,但我们决定采用开源并使用大型社区支持的成熟解决方案。
我们选择背后的原因是:
- 当事情成熟到可以正常工作时,我们喜欢它
- 我们希望从开源框架的广泛集成和定制可能性中受益
- 我们已经使用下面详细描述的工具集成功地满足了验收测试的内部和商业需求。
端到端测试框架
概述
我们的框架旨在支持自动化验收测试,旨在同时适应 API 和 GUI 测试。
它在 JAVA 中实现,如果需要,可以轻松扩展以连接到数据库和消息队列。
场景(与企业主/分析师一起创建)是用 Cucumber(Gherkin 语法)编写的,并被分组为特性。
基于场景标签(指定严重性、组件等)使用 TestNG+CubumberJVM 和 Maven 执行测试。测试可以并行运行;可以使用 TestNG 或 Cucumber hooks 设置测试数据。
引擎盖下是什么?
- Cucumber (Gherkin) –> 场景和功能
- RestAssured -> REST API 步骤定义,
- JAX-WS -> SOAP API 步骤定义,
- Selenium -> GUI 步骤定义
- Zalenium -> 在不同浏览器上运行 GUI 场景,视频录制仪表板
- Allure -> 通用格式 HTML 测试报告
- 支持库:
- Swagger Codegen -> 从 Swagger 生成类模型
- Apache CXF -> 从 WSDL 生成类模型
- Java Faker -> 假数据生成器
- Waiter -> selenium 等待包装器
- TestNG+CucumberJVM, Maven -> 运行测试,钩子之前/之后
- Jenkins (或类似的)-> CI/CD
优点和特点
准备部署
“样板”已准备好部署为本地或云中的 Docker 容器,例如作为 Openshift 或 K8s 项目(这是我们的开箱即用方法中的首选,以实现最高效的执行环境)。
可执行的测试规范
Gherkin 为人类友好的测试规范提供语法,可以作为代码实现和运行。特性、场景和步骤组成了面向业务的测试规范,而步骤定义和支持代码一起执行测试任务。
以下是可执行测试场景的两个示例。
API(基本场景):
GUI (using a Scenario Outline):
请注意,使用数据驱动场景就像在“示例”表中添加新行一样简单!
友好的报告
Allure 为 RestAssured、Cucumber 和 Jenkins 提供美观的 HTML 报告和开箱即用的集成。
我们进一步定制了我们的报告,以提供:
对 GUI 测试执行的视频记录的引用
链接到票据管理系统(例如 JIRA)
需要时,还可以将执行结果报告回 JIRA(通过自定义“@after”钩子)。
最佳实践
以下是实施和执行方案时要遵循的一些最佳实践:
- 场景应与企业主/分析师一起准备,并用 Cucumber (Gherkin) 编写,同时利用其功能,例如:
- 场景大纲和示例
- 数据表
- 标签(例如“@gui”、“@api”、“@blocker”等)
- 场景必须相互独立,即它们中的每一个都应该能够单独运行(测试数据不应“泄漏”到其他场景)
- 场景不应包含不必要的技术细节,并且应该易于理解
- 场景应该根据测试的业务领域分组在 *.feature 文件中(不一定每个用户故事)
- 实现 GUI 步骤定义时:
- 推荐使用页面对象模式
- 禁止“Sleeps”
- id、css 选择器优于 xpath
- 实现 API 步骤定义时:
- 公共属性应与 RestAssured RequestSpecifications 一起重用
- 过滤器应该用于记录
- 只要有可能,应该从 API 定义(.wsdl、.swagger)创建 DTO
- 测试应在专用环境中/使用专用测试数据运行(以避免干扰手动测试)
- 自动生成的数据应加前缀或后缀(以便与手动测试数据分开)
- 应该模拟集成范围之外的系统(我们在环境中无法控制)
为什么不使用 Postman 和 Cypress.io 呢?
Postman(与 Newman 一起)和 Cypress.io 都是很棒的(半商业)工具,尽管有些有限。在大型企业环境中工作,对自动化测试的要求有时会更加苛刻。以 API 测试为例——我们实际上使用 Postman 作为开发(和测试开发)辅助工具,但 RestAssured 让您可以更好地控制测试的组织和执行。
一个很好的例子是我们最近必须涵盖的一个测试场景,它需要控制 SSL 会话。虽然 Postman 在请求之间保持 SSL 会话打开(以不可配置的方式),但 RestAssured 允许您选择是保持 SSL 连接处于活动状态还是在后续请求之后关闭它(通过其 connection-config 方法)。
Cypress.io 的受欢迎程度正在增长,但是当需要完整的浏览器控制(使用选项卡和 iframe)和跨浏览器测试时,Selenium 尽管有缺点,但仍然可以提供更多功能。
(请注意,框架组件可以根据项目需求进行修改和调整)
保持在一起
以下是有关如何充分利用自动化端到端测试的一些更一般的提示。
与您的 CI/CD 管道集成
自动化验收测试应集成到 CI/CD 管道中,作为将应用程序自动部署到专用测试环境(例如使用 OpenShift 项目模板创建)之后的下一步。验收测试失败意味着部署失败!
使您的自动化测试成为开发过程的一部分
自动化测试场景应该与产品开发一起编写。与开发功能并行编写测试(而不是事后才进行测试)将帮助您缩短反馈循环并提供更好的产品。
与利益相关者合作
邀请利益相关者(业务分析师、手动测试人员)参与 BDD 测试场景将使您的团队更好地沟通,甚至可能有助于在将错误/差距转化为代码之前识别它们。无处不在的领域语言将有助于避免误解。
不要重复你自己(和你的测试)
应避免跨不同测试级别重复业务逻辑覆盖。端到端测试应该只涵盖应用程序中最重要的用户旅程。
根据反馈采取行动
在任何测试步骤中发现的错误都应该被测试金字塔最低级别的测试覆盖。
注意执行时间
就 e2e 测试套件执行的时间预算达成一致是个好主意,例如 15 分钟。请记住,您的自动化测试是一个“安全网”,不应使部署过程过长而令人不安。
原文:https://bluesoft.com/acceptance-testing-in-enterprise-environments/
- 29 次浏览
【软件测试】实用测试金字塔
“测试金字塔”是一个比喻,它告诉我们将软件测试分组到不同粒度的桶中。它还给出了我们应该在每个组中进行多少次测试的概念。尽管测试金字塔的概念已经存在了一段时间,但是团队仍然在努力将其正确地付诸实践。本文回顾了测试金字塔的原始概念,并展示了如何将其付诸实践。它显示了您应该在金字塔的不同级别中寻找哪种类型的测试,并给出了如何实现这些测试的实际示例。
生产就绪的软件需要在投入生产之前进行测试。随着软件开发学科的成熟,软件测试方法也日趋成熟。开发团队不再拥有大量的手工软件测试人员,而是将测试工作的大部分自动化。自动化测试使团队能够在几秒钟或几分钟内而不是几天或几周内知道他们的软件是否被破坏。
自动化测试大大缩短了反馈循环,与敏捷开发实践、持续交付和DevOps文化密切相关。拥有一个有效的软件测试方法可以让团队快速而有信心地前进。
本文探讨了一个全面的测试组合应该是什么样子的,以保证响应性、可靠性和可维护性——无论您正在构建的是微服务体系结构、移动应用程序还是物联网生态系统。我们还将讨论构建有效且可读的自动化测试的细节。
(测试)自动化的重要性
软件已经成为我们生活的世界的重要组成部分。它已经超越了其早期的唯一目的——提高企业效率。如今,企业都在想方设法成为一流的数字企业。作为用户,我们每个人每天都在与越来越多的软件进行交互。创新的车轮正在加速转动。
如果你想跟上步伐,你就必须想办法在不牺牲软件质量的前提下更快地交付你的软件。持续交付(Continuous delivery)可以帮助您实现这一点,在这种实践中,您可以自动确保您的软件可以在任何时候发布到生产环境中。通过持续交付,您可以使用构建管道来自动测试您的软件,并将其部署到您的测试和生产环境中。
手工构建、测试和部署越来越多的软件很快就不可能了——除非您想把所有的时间都花在手工的、重复的工作上,而不是交付工作软件。自动化一切——从构建到测试、部署和基础设施——是您前进的唯一道路。
图1:使用构建管道自动可靠地将软件投入生产
传统上,软件测试是过度手工的工作,将应用程序部署到测试环境中,然后执行一些黑箱风格的测试,例如单击用户界面查看是否有损坏。通常这些测试将由测试脚本指定,以确保测试人员执行一致的检查。
很明显,手工测试所有更改是费时、重复和乏味的。重复性工作很无聊,无聊会导致错误,让你在周末之前找一份不同的工作。
幸运的是,对于重复性任务有一个补救方法:自动化。
作为一名软件开发人员,自动化您的重复测试可以极大地改变您的生活。自动化这些测试,您就不再需要盲目地遵循点击协议来检查您的软件是否仍然正常工作。自动化您的测试,您可以毫不费力地更改您的代码基。如果您曾经尝试过在没有适当测试套件的情况下进行大规模重构,我敢打赌您一定知道这是一种多么可怕的体验。如果你在路上不小心弄坏了东西,你怎么知道?好吧,您点击所有的手动测试用例,就是这样。但说实话:你真的喜欢那样吗?如果你能做出更大的改变,知道你是否在喝咖啡的几秒钟内就把东西弄坏了呢?如果你问我,听起来会更有趣。
测试金字塔
如果你想认真对待软件的自动化测试,有一个关键的概念你应该知道:测试金字塔。Mike Cohn在他的书《成功与敏捷》中提出了这个概念。这是一个很好的视觉隐喻,告诉你要考虑不同层次的测试。它还告诉您在每个层上要做多少测试。
图2:测试金字塔
Mike Cohn最初的测试金字塔由三层组成,你的测试套件应该包括(从下到上):
- 单元测试
- 服务测试
- 用户界面测试
不幸的是,如果你仔细看的话,测试金字塔的概念有点短。有些人认为迈克·科恩的测试金字塔的命名或某些概念方面并不理想,我不得不同意这一点。从现代的观点来看,测试金字塔似乎过于简单,因此可能具有误导性。
尽管如此,由于它的简单性,当您建立自己的测试套件时,测试金字塔的本质是一个很好的经验法则。你最好记住科恩最初的测试金字塔中的两件事:
- 编写不同粒度的测试
- 级别越高,应该进行的测试就越少
坚持使用金字塔形状来得到一个健康、快速和可维护的测试套件:编写大量小而快速的单元测试。编写一些更粗粒度的测试和很少的高级测试来从头到尾测试您的应用程序。小心,你不会得到一个测试冰淇淋甜筒,这将是一个噩梦,维护和运行太长时间。
不要过于依赖科恩测试金字塔中各个层的名称。事实上,它们可能非常具有误导性:服务测试是一个很难理解的术语(Cohn自己谈到了许多开发人员完全忽略这一层的观察结果)。在使用react、angular、ember.js等单页面应用程序框架的日子里,UI测试显然不必位于金字塔的最高层——你完全可以在所有这些框架中对UI进行单元测试。
考虑到原始名称的缺点,为测试层提供其他名称是完全可以的,只要在代码库和团队讨论中保持一致即可。
工具和库
- JUnit:我们的测试运行器
- mockkito:用于mock依赖项
- Wiremock:用于清除外部服务
- PACT :用于编写CDC测试
- Selenium:用于编写ui驱动的端到端测试
- REST-assured:用于编写REST api驱动的端到端测试
样例应用程序
我已经编写了一个简单的微服务,包括一个测试套件,其中包含针对测试金字塔不同层的测试。
示例应用程序显示了典型微服务的特征。它提供一个REST接口,与数据库对话并从第三方REST服务获取信息。它是在Spring Boot中实现的,即使您以前从未使用过Spring Boot,也应该能够理解它。
确保在Github上查看代码。readme包含在您的机器上运行应用程序及其自动化测试所需的说明。
功能
应用程序的功能很简单。它提供了一个有三个端点的REST接口:
GET /hello | 返回“Hello World”。总是这样。 |
GET /hello/{lastname} | 查找提供姓氏的人。如果这个人是已知的,返回“Hello {Firstname} {Lastname}”。 |
GET /weather | 返回德国汉堡的当前天气状况。 |
获取/天气返回德国汉堡的当前天气状况。
高层结构
在高层次上,该系统具有以下结构:
图3:我们的微服务系统的高层结构
我们的微服务提供了一个可以通过HTTP调用的REST接口。对于某些端点,服务将从数据库获取信息。在其他情况下,服务将通过HTTP调用外部天气API来获取和显示当前天气条件。
内部架构
在内部,Spring服务有一个典型的Spring架构:
图4:我们的微服务的内部结构
- 控制器类提供REST端点并处理HTTP请求和响应
- Repository类与数据库接口,负责将数据写入或从持久存储中读取
- 客户机类与其他API通信,在我们的示例中,它通过HTTPS从darksky.net weather API获取JSON
- 域类捕获我们的域模型,包括域逻辑(公平地说,在我们的例子中,域逻辑非常简单)。
有经验的Spring开发人员可能会注意到这里缺少一个常用的层:受领域驱动设计的启发,许多开发人员构建了一个由服务类组成的服务层。我决定不在这个应用程序中包含服务层。一个原因是我们的应用程序足够简单,服务层可能是不必要的间接层。另一个原因是我认为人们在服务层上做得太多了。我经常遇到这样的代码库,其中整个业务逻辑都在服务类中捕获。域模型仅仅成为一个数据层,而不是行为层(一个贫血的域模型)。对于每个重要的应用程序,这都浪费了保持代码良好结构和可测试性的大量潜力,并且没有充分利用面向对象的功能。
我们的存储库非常简单,并且提供了简单的CRUD功能。为了保持代码简单,我使用了Spring Data。Spring Data为我们提供了一个简单而通用的CRUD存储库实现,我们可以使用它来代替自己滚动。它还负责为我们的测试构建内存中的数据库,而不是像在生产中那样使用真正的PostgreSQL数据库。
看一下代码库,熟悉一下内部结构。这对于我们下一步:测试应用程序非常有用!
单元测试
测试套件的基础将由单元测试组成。您的单元测试确保代码基的某个单元(您正在测试的主题)按预期工作。在您的测试套件中,单元测试的范围是所有测试中最窄的。测试套件中的单元测试数量将大大超过任何其他类型的测试。
图5:单元测试通常用测试替身替换外部协作者
单位是什么?
如果你问三个不同的人“单元”在单元测试上下文中是什么意思,你可能会得到四个不同的,稍微有些细微差别的答案。在某种程度上,这取决于你自己的定义,没有标准答案也没关系。
如果您使用的是函数式语言,那么单元很可能是单个函数。您的单元测试将调用具有不同参数的函数,并确保它返回预期值。在面向对象的语言中,单元可以从单个方法到整个类。
善于交际和孤独的
一些人认为,所有被测试对象的合作者(例如,被测试类调用的其他类)都应该用mock或stub替换,以实现完美的隔离,并避免副作用和复杂的测试设置。其他人则认为,只有那些速度较慢或副作用较大的协作者(例如访问数据库或进行网络调用的类)才应该被忽略或嘲笑。
偶尔人们会将这两种测试标记为单独的单元测试,用于存根所有协作者的测试,以及用于允许与真正协作者对话的测试的社会性单元测试(Jay Fields有效地使用单元测试创造了这些术语)。如果你有一些空闲时间,你可以深入了解不同学派的优缺点。
在一天结束的时候,决定是进行单独的单元测试还是社交单元测试并不重要。编写自动化测试是重要的。就我个人而言,我发现自己一直在使用这两种方法。如果使用真正的协作者变得很困难,我将大量使用mock和stub。如果我想让真正的合作者参与到测试中来,这会让我在测试中更有信心,那么我只会将服务的最外层存根。
通过模拟和存根
mock和存根是两种不同的测试替身(不止这两种)。许多人将Mock和存根这两个术语互换使用。我认为精确地记住它们的特定性质是有好处的。您可以使用test double用一个帮助您进行测试的实现来替换您在生产中使用的对象。
简单地说,它的意思是用一个伪版本替换一个真实的东西(例如类、模块或函数)。假版本的外观和行为与真实版本类似(对相同方法调用的答案),但是答案包含在单元测试开始时定义的固定响应。
使用测试双精度并不特定于单元测试。可以使用更精细的测试替身以受控的方式模拟系统的整个部分。然而,在单元测试中,您很可能会遇到很多mock和存根(这取决于您是喜欢交际的开发人员还是喜欢独处的开发人员),原因很简单,因为许多现代语言和库使设置mock和存根变得简单和舒适。
无论您选择哪种技术,很有可能您的语言的标准库或一些流行的第三方库将为您提供设置模拟的优雅方法。甚至从头开始编写自己的模拟也只是编写一个具有与实际签名相同的伪类/模块/函数,并在测试中设置伪类/模块/函数。
您的单元测试将运行得非常快。在一台不错的机器上,您可以期望在几分钟内运行数千个单元测试。单独测试代码基的一小部分,避免攻击数据库、文件系统或触发HTTP查询(通过对这些部分使用mock和存根),以保持测试速度。
一旦你掌握了编写单元测试的窍门,你就会越来越熟练地编写它们。排除外部合作者,设置一些输入数据,调用被测试对象,并检查返回的值是否符合您的期望。研究测试驱动开发,让您的单元测试指导您的开发;如果应用正确,它可以帮助您进入一个伟大的流程,并提出一个良好的和可维护的设计,同时自动生成一个全面的和完全自动化的测试套件。不过,这并不是什么灵丹妙药。去吧,给它一个真正的机会,看看它是否适合你。
测试什么?
单元测试的好处是,您可以为所有的生产代码类编写它们,不管它们的功能是什么,也不管它们属于内部结构的哪个层。您可以对控制器进行单元测试,就像您可以对存储库、域类或文件读取器进行单元测试一样。简单地按照每个生产类的经验规则坚持一个测试类,您就有了一个良好的开端。
单元测试类至少应该测试类的公共接口。不能测试私有方法,因为您不能从不同的测试类调用它们。从测试类中可以访问Protected或package-private(假定您的测试类的包结构与生产类相同),但是测试这些方法可能已经走得太远了。
当涉及到编写单元测试时,有一条很好的线:它们应该确保测试了所有非平凡的代码路径(包括幸福路径和边缘用例)。同时,它们不应该与您的实现太紧密地联系在一起。
为什么?
过于接近生产代码的测试很快就会变得令人讨厌。一旦重构了生产代码(快速回顾:重构意味着在不更改外部可见行为的情况下更改代码的内部结构),单元测试就会崩溃。
这样,您就失去了单元测试的一大好处:充当代码更改的安全网。每次重构时,您都会对那些愚蠢的测试失败感到厌倦,导致更多的工作而不是提供帮助;这个愚蠢的测试是谁的主意?
你会怎么做呢?不要在单元测试中反映内部代码结构。测试可观察的行为。思考
如果我输入值x和y,结果会是z吗?
而不是
如果我输入x和y,这个方法会先调用类A,然后调用类B,然后返回类A的结果加上类B的结果吗?
通常应该将私有方法视为实现细节。这就是为什么你甚至不应该有测试它们的冲动。
我经常听到反对单元测试(或TDD)的人说,编写单元测试是没有意义的工作,您必须测试所有方法才能得到一个高测试覆盖率。他们经常引用一些场景,在这些场景中,过于热切的团队领导强迫他们为getter和setter以及所有其他类型的琐碎代码编写单元测试,以便获得100%的测试覆盖率。
这有很多问题。
是的,您应该测试公共接口。然而,更重要的是,您不测试普通的代码。别担心,肯特·贝克说没事的。测试简单的getter或setter或其他简单的实现(例如,没有任何条件逻辑)不会给您带来任何好处。节省时间,这是你可以参加的另一个会议,万岁!
但我真的需要测试这个私有方法
如果你发现自己真的需要测试一个私有方法,你应该退一步问问自己为什么。
我很确定这更多的是一个设计问题而不是范围问题。很可能您觉得需要测试一个私有方法,因为它很复杂,并且通过类的公共接口测试这个方法需要进行很多笨拙的设置。
每当我发现自己处于这种情况时,我通常会得出这样的结论:我正在测试的类已经太复杂了。它做得太多,违反了单一的责任原则——五项基本原则的原则。
通常对我有效的解决方案是将原来的类分成两个类。通常只需要一到两分钟的思考就能找到一个好方法,把一个大班分成两个小班,每个班都有自己的责任。我将私有方法(我迫切需要测试的方法)移动到新类,并让旧类调用新方法。瞧,我的私有测试方法现在是公共的,可以很容易地进行测试。除此之外,我还通过坚持单一职责原则改进了代码的结构。
测试结构
一个适用于所有测试(不限于单元测试)的良好结构是:
- 设置测试数据
- 调用正在测试的方法
- 断言返回了预期的结果
有一个很好的助记符来记住这个结构:“Arrange, Act, Assert”。您可以使用的另一个方法是从BDD中获得灵感。它是“given”、“when”、“then”三元组,其中given表示设置,when方法调用,然后是断言部分。
这种模式也可以应用于其他更高级的测试。在每种情况下,它们都确保您的测试保持简单和一致。最重要的是,用这种结构编写的测试往往更短,更有表现力。
实现单元测试
现在我们知道了要测试什么以及如何构建单元测试,我们终于可以看到一个真实的例子了。
让我们以ExampleController类的简化版本为例:
@RestController public class ExampleController { private final PersonRepository personRepo; @Autowired public ExampleController(final PersonRepository personRepo) { this.personRepo = personRepo; } @GetMapping("/hello/{lastName}") public String hello(@PathVariable final String lastName) { Optional<Person> foundPerson = personRepo.findByLastName(lastName); return foundPerson .map(person -> String.format("Hello %s %s!", person.getFirstName(), person.getLastName())) .orElse(String.format("Who is this '%s' you're talking about?", lastName)); } }
hello(lastname)方法的单元测试可能是这样的:
public class ExampleControllerTest { private ExampleController subject; @Mock private PersonRepository personRepo; @Before public void setUp() throws Exception { initMocks(this); subject = new ExampleController(personRepo); } @Test public void shouldReturnFullNameOfAPerson() throws Exception { Person peter = new Person("Peter", "Pan"); given(personRepo.findByLastName("Pan")) .willReturn(Optional.of(peter)); String greeting = subject.hello("Pan"); assertThat(greeting, is("Hello Peter Pan!")); } @Test public void shouldTellIfPersonIsUnknown() throws Exception { given(personRepo.findByLastName(anyString())) .willReturn(Optional.empty()); String greeting = subject.hello("Pan"); assertThat(greeting, is("Who is this 'Pan' you're talking about?")); } }
我们使用JUnit编写单元测试,JUnit实际上是Java的标准测试框架。我们使用Mockito将实际的PersonRepository类替换为测试的存根。这个存根允许我们定义存根方法在这个测试中应该返回的固定响应。存根使我们的测试更加简单、可预测,并允许我们轻松地设置测试数据。
按照arrangement、act、assert结构,我们编写了两个单元测试——一个是阳性的情况,另一个是无法找到被搜索的人的情况。第一个测试用例创建了一个新的person对象,并告诉模拟存储库在调用该对象时返回该对象,并将“Pan”作为lastName参数的值。然后测试继续调用应该测试的方法。最后,它断言响应等于预期的响应。
第二个测试的工作原理类似,但是测试的方法没有为给定的参数找到person。
集成测试
所有重要的应用程序都将与其他部分集成(数据库、文件系统、对其他应用程序的网络调用)。在编写单元测试时,为了得到更好的隔离性和更快的测试,您通常会遗漏这些部分。不过,您的应用程序将与其他部分进行交互,这需要进行测试。集成测试可以提供帮助。它们测试应用程序与应用程序外部的所有部分的集成。
对于自动化测试,这意味着您不仅需要运行自己的应用程序,还需要运行与之集成的组件。如果要测试与数据库的集成,则需要在运行测试时运行数据库。为了测试您是否可以从磁盘读取文件,您需要将文件保存到磁盘并在集成测试中加载它。
我之前提到过“单元测试”是一个模糊的术语,对于“集成测试”更是如此。对于某些人来说,集成测试意味着通过连接到系统中其他应用程序的整个应用程序堆栈进行测试。我喜欢更严格地对待集成测试,每次测试一个集成点,用测试替身替换单独的服务和数据库。结合契约测试和对测试加倍运行契约测试,以及实际实现,您可以得到更快、更独立、通常更容易推理的集成测试。
窄集成测试位于服务的边界。从概念上讲,它们总是触发导致与外部部分(文件系统、数据库、独立服务)集成的操作。数据库集成测试应该是这样的:
图6:数据库集成测试将您的代码与实际数据库集成
- 启动数据库
- 将应用程序连接到数据库
- 在代码中触发一个函数,该函数将数据写入数据库
- 通过从数据库中读取数据,检查预期的数据是否已写入数据库
另一个例子,测试你的服务通过一个REST API集成到一个单独的服务可能是这样的:
图7:这种集成测试检查应用程序是否能够正确地与单独的服务通信
- 启动您的应用程序
- 启动独立服务的实例(或具有相同接口的测试double)
- 在代码中触发从独立服务的API读取的函数
- 检查应用程序能否正确解析响应
您的集成测试—就像单元测试—可以是相当白盒的。一些框架允许您启动应用程序,同时仍然能够模拟应用程序的其他部分,以便检查是否发生了正确的交互。
为序列化或反序列化数据的所有代码段编写集成测试。这种情况发生的频率比你想象的要高。思考:
- 调用服务的REST API
- 读取和写入数据库
- 调用其他应用程序的api
- 读取和写入队列
- 写入文件系统
围绕这些边界编写集成测试可以确保向这些外部协作者编写数据和从这些外部协作者读取数据的工作正常。
在编写窄范围集成测试时,您的目标应该是在本地运行外部依赖项:启动本地MySQL数据库,在本地ext4文件系统上进行测试。如果要与单独的服务集成,要么在本地运行该服务的实例,要么构建并运行一个模仿真实服务行为的伪版本。
如果无法在本地运行第三方服务,您应该选择运行专用的测试实例,并在运行集成测试时指向该测试实例。避免在自动化测试中与实际生产系统集成。对生产系统发出数千个测试请求肯定会引起人们的愤怒,因为您弄乱了他们的日志(在最好的情况下),甚至拒绝了他们的服务(在最坏的情况下)。通过网络与服务集成是广泛集成测试的一个典型特征,这会使您的测试速度变慢,并且通常更难编写。
关于测试金字塔,集成测试比单元测试处于更高的级别。集成较慢的部分(如文件系统和数据库)往往比运行单元测试时将这些部分去掉要慢得多。它们也比小型和独立的单元测试更难编写,毕竟您必须将外部部分作为测试的一部分来处理。尽管如此,它们的优点是让您相信您的应用程序可以正确地处理它需要与之通信的所有外部部分。单元测试在这方面帮不了你。
数据库集成
PersonRepository是代码库中惟一的repository类。它依赖于Spring数据,没有实际的实现。它只是扩展了CrudRepository接口并提供了一个方法头。剩下的就是春天的魔力。
public interface PersonRepository extends CrudRepository<Person, String> { Optional<Person> findByLastName(String lastName); }
通过CrudRepository接口,Spring Boot提供了一个功能齐全的CRUD存储库,其中包含findOne、findAll、save、update和delete方法。我们的自定义方法定义(findByLastName())扩展了这一基本功能,并为我们提供了一种按姓氏获取人员的方法。Spring Data分析方法的返回类型及其方法名,并根据命名约定检查方法名,以确定它应该做什么。
尽管Spring Data承担了实现数据库存储库的重任,但我仍然编写了一个数据库集成测试。您可能会认为这是在测试框架,我应该避免这样做,因为我们测试的不是我们的代码。尽管如此,我相信这里至少有一个集成测试是至关重要的。首先,它测试自定义findByLastName方法的实际行为是否符合预期。其次,证明了我们的存储库正确使用了Spring的连接,可以连接到数据库。
为了让您更容易地在您的机器上运行测试(无需安装PostgreSQL数据库),我们的测试连接到内存中的H2数据库。
我将H2定义为构建中的一个测试依赖项。gradle文件。应用程序。测试目录中的属性不定义任何spring。数据源的属性。这告诉Spring Data使用内存中的数据库。当它在类路径中找到H2时,它在运行我们的测试时只使用H2。
当运行带有int概要文件的实际应用程序时(例如,通过将SPRING_PROFILES_ACTIVE=int作为环境变量),它连接到应用程序int.properties中定义的PostgreSQL数据库。
我知道,有很多Spring的细节需要了解和理解。要做到这一点,你必须仔细阅读大量的文档。生成的代码看起来很简单,但是如果不了解Spring的详细信息,就很难理解。
除此之外,使用内存数据库是有风险的。毕竟,我们的集成测试运行在与生产环境不同的数据库类型上。您可以自己决定是否更喜欢Spring magic和简单的代码,而不是显式的更详细的实现。
已经有足够的解释了,下面是一个简单的集成测试,它将一个人保存到数据库中,并根据他的姓找到他:
@RunWith(SpringRunner.class) @DataJpaTest public class PersonRepositoryIntegrationTest { @Autowired private PersonRepository subject; @After public void tearDown() throws Exception { subject.deleteAll(); } @Test public void shouldSaveAndFetchPerson() throws Exception { Person peter = new Person("Peter", "Pan"); subject.save(peter); Optional<Person> maybePeter = subject.findByLastName("Pan"); assertThat(maybePeter, is(Optional.of(peter))); } }
您可以看到,我们的集成测试遵循与单元测试相同的安排、行为和断言结构。告诉你这是一个普遍的概念!
与独立服务集成
我们的微服务与darksky.net对话,后者是一个天气REST API。当然,我们希望确保我们的服务发送请求并正确解析响应。
在运行自动化测试时,我们希望避免触及真正的darksky服务器。我们免费计划的配额限制只是部分原因。真正的原因是脱钩。我们的测试应该独立于darksky.net上那些可爱的人正在做的事情。即使您的机器无法访问darksky服务器或darksky服务器停机进行维护。
我们可以在运行集成测试时运行我们自己的、假的darksky服务器,从而避免触及真正的darksky服务器。这听起来像是一项艰巨的任务。多亏了像Wiremock这样的工具,这很容易。看这个:
@RunWith(SpringRunner.class) @SpringBootTest public class WeatherClientIntegrationTest { @Autowired private WeatherClient subject; @Rule public WireMockRule wireMockRule = new WireMockRule(8089); @Test public void shouldCallWeatherService() throws Exception { wireMockRule.stubFor(get(urlPathEqualTo("/some-test-api-key/53.5511,9.9937")) .willReturn(aResponse() .withBody(FileLoader.read("classpath:weatherApiResponse.json")) .withHeader(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .withStatus(200))); Optional<WeatherResponse> weatherResponse = subject.fetchWeather(); Optional<WeatherResponse> expectedResponse = Optional.of(new WeatherResponse("Rain")); assertThat(weatherResponse, is(expectedResponse)); } }
为了使用Wiremock,我们在一个固定端口(8089)上实例化一个WireMockRule。使用DSL,我们可以设置Wiremock服务器,定义它应该监听的端点,并设置它应该使用的固定响应。
接下来,我们调用要测试的方法,即调用第三方服务的方法,并检查结果是否正确解析。
理解测试如何知道它应该调用伪Wiremock服务器而不是真正的darksky API是很重要的。秘密就在我们的申请中。包含在src/test/resources中的属性文件。这是运行测试时Spring加载的属性文件。在这个文件中,我们覆盖的配置,如API键和url的值适合我们的测试目的,例如调用假的Wiremock服务器,而不是真正的:
weather.url = http://localhost:8089
注意,这里定义的端口必须与我们在测试中实例化WireMockRule时定义的端口相同。在我们的测试中,通过在WeatherClient类的构造函数中注入URL,可以用一个假的URL替换真实天气API的URL:
@Autowired public WeatherClient(final RestTemplate restTemplate, @Value("${weather.url}") final String weatherServiceUrl, @Value("${weather.api_key}") final String weatherServiceApiKey) { this.restTemplate = restTemplate; this.weatherServiceUrl = weatherServiceUrl; this.weatherServiceApiKey = weatherServiceApiKey; }
通过这种方式,我们告诉WeatherClient从天气中读取weatherUrl参数的值。我们在应用程序属性中定义url属性。
使用Wiremock之类的工具,为单独的服务编写窄范围的集成测试非常容易。不幸的是,这种方法有一个缺点:如何确保我们设置的假服务器的行为与真实服务器一样?使用当前的实现,单独的服务可以更改它的API,我们的测试仍然可以通过。现在,我们只是在测试我们的WeatherClient是否能够解析伪服务器发送的响应。这是一个开始,但它很脆弱。使用端到端测试并针对真实服务的测试实例运行测试,而不是使用虚假服务,可以解决这个问题,但是会使我们依赖于测试服务的可用性。幸运的是,对于这个困境有一个更好的解决方案:对伪服务器和真实服务器运行契约测试,确保我们在集成测试中使用的伪服务器是一个忠实的测试副本。接下来让我们看看它是如何工作的。
合同的测试
更现代的软件开发组织已经找到了通过将系统开发分散到不同的团队来扩展开发工作的方法。单独的团队构建单独的、松散耦合的服务,而不需要彼此介入,并将这些服务集成到一个大型的、内聚的系统中。最近围绕微服务的热议正聚焦于此。
将您的系统分割为许多小型服务通常意味着这些服务需要通过某些接口(希望定义良好,有时意外地增长)彼此通信。
不同应用程序之间的接口可以有不同的形状和技术。常见的是
- 通过HTTPS实现REST和JSON
- 使用诸如gRPC之类的东西的RPC
- 使用队列构建事件驱动的体系结构
对于每个接口,都涉及两个方面:提供者和使用者。提供者向使用者提供数据。使用者处理从提供者获得的数据。在REST世界中,提供者使用所有需要的端点构建一个REST API;使用者调用此REST API来获取数据或触发其他服务中的更改。在异步的、事件驱动的世界中,提供者(通常称为发布者)将数据发布到队列;使用者(通常称为订阅者)订阅这些队列并读取和处理数据。
图8:每个接口都有一个提供方(或发布方)和一个消费方(或订阅方)。接口的规范可以看作是契约。
由于您经常将消费和提供服务分散到不同的团队中,您会发现必须清楚地指定这些服务之间的接口(所谓的契约)。传统上,公司处理这个问题的方法如下:
- 编写一个长而详细的接口规范(合同)
- 根据定义的合同实现提供的服务
- 将接口规范抛给消费团队
- 等待,直到它们实现使用接口的那一部分
- 运行一些大型手动系统测试,看看是否一切正常
- 希望两个团队永远坚持接口定义,不要搞砸
更现代的软件开发团队已经取代了步骤5。和6。使用更自动化的东西:自动化契约测试确保消费者和提供者端上的实现仍然坚持已定义的契约。它们可以作为一个很好的回归测试套件,并确保尽早发现与契约的偏差。
在一个更敏捷的组织中,你应该采取更有效和更少浪费的方式。您在同一个组织中构建应用程序。与其他服务的开发人员直接对话,而不是将过于详细的文档抛到一边,应该不会太难。毕竟,他们是你的同事,而不是你只能通过客户支持或合法的防弹合同与之交谈的第三方供应商。
消费者驱动的契约测试(CDC测试)让消费者驱动契约的实现。使用CDC,接口的使用者编写测试,检查接口中所需的所有数据。然后,消费团队发布这些测试,以便发布团队能够轻松地获取和执行这些测试。现在,提供团队可以通过运行CDC测试来开发他们的API。一旦所有测试通过,他们就知道已经实现了消费团队所需的所有东西。
图9:契约测试确保接口的提供者和所有使用者都遵守定义的接口契约。在CDC测试中,接口的消费者以自动化测试的形式发布他们的需求;提供者不断地获取和执行这些测试
这种方法允许提供团队只实现真正需要的东西(保持事情简单,YAGNI等等)。提供接口的团队应该连续获取并运行这些CDC测试(在他们的构建管道中),以立即发现任何中断的更改。如果他们破坏了接口,他们的CDC测试就会失败,从而阻止破坏的更改生效。只要测试保持绿色,团队就可以进行他们喜欢的任何更改,而不必担心其他团队。消费者驱动的契约方法将使您的流程如下:
- 消费团队编写具有所有消费者期望的自动化测试
- 他们为提供团队发布测试
- 提供团队持续运行CDC测试并保持测试绿色
- 一旦CDC测试中断,两个团队就会互相交谈
如果您的组织采用微服务方法,那么进行CDC测试是建立自治团队的重要一步。CDC测试是一种促进团队沟通的自动化方法。它们确保团队之间的接口在任何时候都能正常工作。失败的CDC测试是一个很好的指示器,说明您应该走到受影响的团队,与他们讨论任何即将发生的API更改,并确定您希望如何继续前进。
CDC测试的简单实现可以简单到针对API发出请求并断言响应包含所需的所有内容。然后将这些测试打包为可执行文件(。并将其上传到其他团队可以获取它的地方(例如,像 Artifactory这样的工件存储库)。
在过去的几年里,CDC的方法变得越来越流行,并且开发了一些工具来简化编写和交换。
Pact可能是这些天来最突出的一个。它有一种为消费者和提供者编写测试的复杂方法,为独立的服务提供开箱即用的存根,并允许您与其他团队交换CDC测试。Pact已经被移植到许多平台上,可以与JVM语言、Ruby、. net、JavaScript以及更多其他语言一起使用。
如果你想从信用违约掉期开始,却不知道如何开始,那么签订协议可能是一个明智的选择。一开始, documentation可能非常多。要有耐心,并坚持到底。它有助于对CDCs有一个牢固的了解,从而使您在与其他团队合作时更容易提倡使用CDCs。
消费者驱动的契约测试可以真正改变游戏规则,从而建立能够快速且自信地行动的自主团队。帮你自己一个忙,通读一下这个概念并试一试。一套可靠的CDC测试是非常宝贵的,它能够在不破坏其他服务和对其他团队造成很多挫折的情况下快速移动。
消费者测试(我们的团队)
我们的微服务使用天气API。因此,编写一个消费者测试是我们的责任,它定义了我们对微服务和天气服务之间的契约(API)的期望。
首先,我们在我们的建筑中包含了一个用于编写契约消费者测试的库。
testCompile (“au.com.dius: pact-jvm-consumer-junit_2.11:3.5.5”)
多亏了这个库,我们可以实现一个消费者测试和使用pact的模拟服务:
@RunWith(SpringRunner.class) @SpringBootTest public class WeatherClientConsumerTest { @Autowired private WeatherClient weatherClient; @Rule public PactProviderRuleMk2 weatherProvider = new PactProviderRuleMk2("weather_provider", "localhost", 8089, this); @Pact(consumer="test_consumer") public RequestResponsePact createPact(PactDslWithProvider builder) throws IOException { return builder .given("weather forecast data") .uponReceiving("a request for a weather request for Hamburg") .path("/some-test-api-key/53.5511,9.9937") .method("GET") .willRespondWith() .status(200) .body(FileLoader.read("classpath:weatherApiResponse.json"), ContentType.APPLICATION_JSON) .toPact(); } @Test @PactVerification("weather_provider") public void shouldFetchWeatherInformation() throws Exception { Optional<WeatherResponse> weatherResponse = weatherClient.fetchWeather(); assertThat(weatherResponse.isPresent(), is(true)); assertThat(weatherResponse.get().getSummary(), is("Rain")); } }
如果您仔细观察,您会发现WeatherClientConsumerTest与WeatherClientIntegrationTest非常相似。这次我们使用Pact代替Wiremock作为服务器存根。事实上,消费者测试与集成测试完全一样,我们用存根替换真正的第三方服务器,定义预期的响应,并检查客户机是否能够正确解析响应。在这个意义上,WeatherClientConsumerTest本身就是一个狭窄的集成测试。与基于wiremock的测试相比,该测试的优点是每次运行时都会生成一个协议文件(可以在target/pacts/&pact-name>.json中找到)。这个契约文件以一种特殊的JSON格式描述了我们对契约的期望。然后可以使用这个契约文件来验证存根服务器的行为是否与真正的服务器一样。我们可以将契约文件交给提供接口的团队。他们使用这个契约文件并使用其中定义的期望编写一个提供者测试。通过这种方式,他们测试他们的API是否满足我们的所有期望。
这就是CDC的消费者驱动部分的来源。消费者通过描述他们的期望来驱动接口的实现。提供者必须确保它们满足所有的期望,并且它们已经完成。没有镀金,没有雅格尼之类的东西。
将契约文件提供给团队可以通过多种方式进行。一个简单的方法是将它们签入版本控制并告诉提供程序团队始终获取最新版本的pact文件。更先进的方法是使用工件存储库,如Amazon的S3或pact broker之类的服务。从简单的开始,根据你的需要成长。
在实际的应用程序中,不需要同时进行集成测试和客户端类的消费者测试。示例代码基包含这两个代码基,以向您展示如何使用其中一个。如果您想使用pact编写CDC测试,我建议坚持使用后者。编写测试的工作是相同的。使用pact的好处是,您可以自动获得一个pact文件,其中包含对契约的期望,其他团队可以使用该文件轻松地实现他们的提供者测试。当然,只有当你能够说服其他团队也使用pact时,这才有意义。如果这不起作用,使用集成测试和Wiremock组合是一个不错的方案b。
提供者测试(另一个团队)
提供者测试必须由提供weather API的人员实现。我们正在使用一个由darksky.net提供的公共API。理论上,darksky团队将在他们的端上实现提供者测试,以检查他们是否违反了他们的应用程序和我们的服务之间的契约。
很明显,他们不关心我们可怜的样本应用程序,也不会为我们实现CDC测试。这就是面向公众的API和采用微服务的组织之间的巨大区别。面向公众的api不能考虑每一个消费者,否则它们将无法前进。在你自己的组织中,你可以而且应该这么做。你的应用很可能只服务少数人,最多几十个消费者。为了保持系统稳定,您可以为这些接口编写提供者测试。
提供团队获取契约文件并对其提供的服务运行它。为此,它们实现了一个提供者测试,该测试读取契约文件,生成一些测试数据,并对它们的服务运行契约文件中定义的期望。
契约人员编写了几个库来实现提供者测试。他们的主要GitHub repo为您提供了一个很好的概述:哪些消费者和哪些提供者库可用。选择一个最适合你的技术堆栈。
为了简单起见,我们假设darksky API也在Spring Boot中实现。在这种情况下,他们可以使用Spring pact提供程序,它很好地挂钩到Spring的MockMVC机制。darksky.net团队将实现的一个假设的提供者测试可能是这样的:
@RunWith(RestPactRunner.class) @Provider("weather_provider") // same as the "provider_name" in our clientConsumerTest @PactFolder("target/pacts") // tells pact where to load the pact files from public class WeatherProviderTest { @InjectMocks private ForecastController forecastController = new ForecastController(); @Mock private ForecastService forecastService; @TestTarget public final MockMvcTarget target = new MockMvcTarget(); @Before public void before() { initMocks(this); target.setControllers(forecastController); } @State("weather forecast data") // same as the "given()" in our clientConsumerTest public void weatherForecastData() { when(forecastService.fetchForecastFor(any(String.class), any(String.class))) .thenReturn(weatherForecast("Rain")); } }
您可以看到,提供者测试所要做的就是加载一个契约文件(例如,通过使用@PactFolder注释来加载以前下载的契约文件),然后定义应该如何提供预定义状态的测试数据(例如,使用Mockito mocks)。没有要实现的自定义测试。这些都是从契约文件派生出来的。提供者测试必须具有与使用者测试中声明的提供者名称和状态匹配的对应项。
供应商测试(我们的团队)
我们已经了解了如何测试我们的服务和天气提供商之间的契约。通过这个接口,我们的服务充当消费者,天气服务充当提供者。进一步考虑一下,我们将看到我们的服务还充当了其他服务的提供者:我们提供了一个REST API,它提供了几个端点,可以供其他服务使用。
由于我们刚刚了解到契约测试非常流行,所以我们当然也为这个契约编写了一个契约测试。幸运的是,我们使用的是消费者驱动的契约,所以所有的消费团队都向我们发送了他们的契约,我们可以使用这些契约来实现REST API的提供者测试。
让我们先把Spring的Pact provider库添加到我们的项目中:
testCompile (“au.com.dius: pact-jvm-provider-spring_2.12:3.5.5”)
实现提供者测试遵循与前面描述的相同的模式。为了简单起见,我只是将契约文件从简单的使用者签入服务的存储库。这使我们的目的更容易实现,在真实的场景中,您可能要使用更复杂的机制来分发约定文件。
@RunWith(RestPactRunner.class) @Provider("person_provider")// same as in the "provider_name" part in our pact file @PactFolder("target/pacts") // tells pact where to load the pact files from public class ExampleProviderTest { @Mock private PersonRepository personRepository; @Mock private WeatherClient weatherClient; private ExampleController exampleController; @TestTarget public final MockMvcTarget target = new MockMvcTarget(); @Before public void before() { initMocks(this); exampleController = new ExampleController(personRepository, weatherClient); target.setControllers(exampleController); } @State("person data") // same as the "given()" part in our consumer test public void personData() { Person peterPan = new Person("Peter", "Pan"); when(personRepository.findByLastName("Pan")).thenReturn(Optional.of (peterPan)); } }
所示的ExampleProviderTest需要根据给定的契约文件提供状态,仅此而已。一旦运行提供者测试,Pact将获取Pact文件并对我们的服务发出HTTP请求,然后根据我们设置的状态进行响应。
用户界面测试
大多数应用程序都有某种用户界面。通常,我们在web应用程序上下文中讨论的是web接口。人们常常忘记,REST API或命令行界面与web用户界面一样,都是用户界面。
UI测试测试应用程序的用户界面是否正常工作。用户输入应该触发正确的动作,数据应该呈现给用户,UI状态应该按照预期进行更改。
UI测试和端到端测试有时(如Mike Cohn的例子)被认为是同一件事。对我来说,这合并了两个相当正交的概念。
是的,端到端测试应用程序通常意味着通过用户界面驱动测试。然而,反过来说就不成立了。
测试用户界面不需要以端到端方式完成。根据使用的技术不同,测试用户界面可以非常简单,只需为前端javascript代码编写一些单元测试,并去掉后端代码。
对于传统的web应用程序,可以使用Selenium等工具来测试用户界面。如果您认为REST API是您的用户界面,那么您应该通过围绕API编写适当的集成测试来获得所需的一切。
对于web界面,您可能希望围绕UI测试多个方面:行为、布局、可用性或对公司设计的坚持性只是其中的几个方面。
幸运的是,测试用户界面的行为非常简单。单击这里,在那里输入数据,并希望用户界面的状态相应地更改。现代单页应用程序框架(react, vue)。js、Angular等等)通常都自带工具和助手,它们允许您以一种相当低层次(单元测试)的方式彻底测试这些交互。即使您使用普通javascript滚动自己的前端实现,也可以使用常规的测试工具,如Jasmine或Mocha。对于更传统的服务器端呈现应用程序,基于硒的测试将是您的最佳选择。
测试web应用程序的布局是否保持不变要稍微困难一些。根据您的应用程序和用户的需要,您可能希望确保代码更改不会意外破坏网站的布局。
问题在于,计算机在检查某样东西是否“看起来不错”方面出了名的糟糕(也许一些聪明的机器学习算法可以在未来改变这一点)。
如果您想在构建管道中自动检查web应用程序的设计,可以尝试一些工具。这些工具中的大多数都使用Selenium以不同的浏览器和格式打开web应用程序,进行截图,并将这些截图与之前的截图进行比较。如果旧截图和新截图有意想不到的不同,这个工具会让你知道。
盖伦就是这些工具之一。但是,如果您有特殊的需求,即使使用您自己的解决方案也不是太难。我与构建阵容及其基于java的近亲j阵容合作过的一些团队也实现了类似的目标。这两个工具都采用了我前面描述的基于selenium的方法。
一旦您想要测试可用性和“看起来不错”的因素,您就离开了自动化测试领域。在这个领域,您应该依赖探索性测试、可用性测试(甚至可以像走廊测试一样简单),并向用户展示他们是否喜欢使用您的产品,以及是否可以使用所有特性而不会感到沮丧或烦恼。
端到端测试
通过已部署的应用程序的用户界面进行测试是您可以测试应用程序的最端到端方式。前面描述的webdriver驱动的UI测试是端到端测试的一个很好的例子。
图11:端到端测试测试整个、完全集成的系统
端到端测试(也称为广义堆栈测试)在您需要决定软件是否工作时给您最大的信心。Selenium和WebDriver协议允许您通过对已部署的服务自动驱动(无头)浏览器、执行单击、输入数据和检查用户界面状态来自动化测试。您可以直接使用Selenium,或者使用构建在它之上的工具,夜视就是其中之一。
端到端测试本身也有一些问题。他们是出了名的脆弱,经常因为意想不到和无法预见的原因而失败。他们的失败往往是一种错误的肯定。用户界面越复杂,测试就越脆弱。浏览器的怪圈、计时问题、动画和意想不到的弹出对话框只是让我花了比我愿意承认的更多时间进行调试的部分原因。
在微服务世界中,还有一个大问题是谁负责编写这些测试。因为它们跨越多个服务(您的整个系统),所以没有一个团队负责编写端到端测试。
如果你有一个集中的质量保证团队,他们看起来很合适。同样,拥有一个集中的QA团队是一个很大的反模式,不应该在DevOps世界中占有一席之地,因为在DevOps世界中,您的团队应该是真正跨功能的。谁应该拥有端到端测试并没有简单的答案。也许您的组织有一个实践社区或质量协会可以处理这些问题。找到正确答案在很大程度上取决于您的组织。
此外,端到端测试需要大量的维护,运行速度非常慢。考虑一个有多个微服务的场景,您甚至不能在本地运行端到端测试——因为这也需要在本地启动所有微服务。祝您在开发机器上运行数百个应用程序时好运,而不会破坏RAM。
由于它们的高维护成本,您应该将端到端测试的数量减少到最小。
考虑用户与应用程序之间的高价值交互。尝试提出定义产品核心价值的用户旅程,并将这些用户旅程中最重要的步骤转换为自动化的端到端测试。
如果你正在建立一个电子商务网站,你最有价值的客户旅程可能是一个用户搜索产品,把它放在购物篮和结帐。就是这样。只要这次旅行还有效,你就不会有太大的麻烦。也许您会发现一个或两个更重要的用户旅程,您可以将它们转换为端到端测试。任何超过这一点的事情都可能是痛苦多于有益的。
记住:在您的测试金字塔中有许多较低的级别,您已经测试了各种边缘用例以及与系统其他部分的集成。没有必要在更高的级别上重复这些测试。高维护工作量和大量的误报会降低您的速度,并导致您对测试失去信任,这迟早都会发生。
用户界面端到端测试
对于端到端测试,Selenium和WebDriver协议是许多开发人员选择的工具。使用Selenium,您可以选择一个您喜欢的浏览器,让它自动调用您的网站,点击这里和那里,输入数据,并检查用户界面中的内容是否发生了更改。
Selenium需要一个可以启动并用于运行测试的浏览器。对于不同的浏览器,您可以使用多个所谓的“驱动程序”。选择一个(或多个)并将其添加到build.gradle中。无论选择哪种浏览器,都需要确保团队和CI服务器中的所有开发人员都在本地安装了正确版本的浏览器。保持同步可能会很痛苦。对于Java,有一个叫做webdrivermanager的小库,可以自动下载并设置您想使用的浏览器的正确版本。将这两个依赖项添加到构建中。格勒德,你可以走了:
testCompile (“org.seleniumhq.selenium: selenium-chrome-driver: 2.53.1”)
testCompile (“io.github.bonigarcia: webdrivermanager: 1.7.2”)
在您的测试套件中运行一个功能齐全的浏览器可能会很麻烦。特别是在使用连续交付时,运行管道的服务器可能无法启动包含用户界面的浏览器(例如,因为没有可用的X-Server)。您可以通过启动像xvfb这样的虚拟x服务器来解决这个问题。
最近的一种方法是使用无头浏览器(即没有用户界面的浏览器)来运行web驱动程序测试。直到最近PhantomJS还是领先的用于浏览器自动化的无头浏览器。自从Chromium和Firefox都宣布在他们的浏览器PhantomJS中实现了无头模式后,PhantomJS突然就过时了。毕竟,最好使用用户实际使用的浏览器(比如Firefox和Chrome)来测试您的网站,而不是使用人工浏览器,因为这对开发人员来说很方便。
无头火狐和Chrome都是全新的浏览器,还没有被广泛应用于webdriver测试。我们想让事情变得简单。让我们坚持使用Selenium和常规浏览器的经典方式,而不是使用最前沿的无头模式。一个简单的端到端测试,启动Chrome,导航到我们的服务,并检查网站的内容如下:
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class HelloE2ESeleniumTest { private WebDriver driver; @LocalServerPort private int port; @BeforeClass public static void setUpClass() throws Exception { ChromeDriverManager.getInstance().setup(); } @Before public void setUp() throws Exception { driver = new ChromeDriver(); } @After public void tearDown() { driver.close(); } @Test public void helloPageHasTextHelloWorld() { driver.get(String.format("http://127.0.0.1:%s/hello", port)); assertThat(driver.findElement(By.tagName("body")).getText(), containsString("Hello World!")); } }
请注意,只有在运行此测试的系统(本地机器、CI服务器)上安装了Chrome,此测试才会在您的系统上运行。
测试很简单。它使用@SpringBootTest在一个随机端口上启动整个Spring应用程序。然后,我们实例化一个新的Chrome webdriver,让它导航到我们的微服务的/hello端点,并检查它是否在浏览器窗口上打印“hello World!”酷炫的东西!
REST API端到端测试
在测试应用程序时避免使用图形用户界面,这是一个好主意,因为这样的测试比完整的端到端测试更可靠,同时仍然覆盖应用程序堆栈的大部分。当通过应用程序的web界面进行测试特别困难时,这一点非常有用。也许您甚至没有web UI,而是提供了一个REST API(因为您有一个单独的页面应用程序在某个地方与该API对话,或者仅仅因为您轻视所有漂亮的东西)。无论哪种方式,一种皮下测试,它只在图形用户界面下进行测试,可以让你在不损害信心的情况下走得更远。如果你提供的是REST API,就像我们在示例代码中所做的那样,那么这是正确的:
@RestController public class ExampleController { private final PersonRepository personRepository; // shortened for clarity @GetMapping("/hello/{lastName}") public String hello(@PathVariable final String lastName) { Optional<Person> foundPerson = personRepository.findByLastName(lastName); return foundPerson .map(person -> String.format("Hello %s %s!", person.getFirstName(), person.getLastName())) .orElse(String.format("Who is this '%s' you're talking about?", lastName)); } }
让我再向您展示一个库,它在测试提供REST API的服务时非常有用。REST-assured是一个库,它为您提供了一个良好的DSL,用于针对API触发真正的HTTP请求并评估您收到的响应。
首先:将依赖项添加到build.gradle。
testCompile('io.rest-assured:rest-assured:3.0.3')
有了这个库,我们可以为我们的REST API实现端到端的测试:
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class HelloE2ERestTest { @Autowired private PersonRepository personRepository; @LocalServerPort private int port; @After public void tearDown() throws Exception { personRepository.deleteAll(); } @Test public void shouldReturnGreeting() throws Exception { Person peter = new Person("Peter", "Pan"); personRepository.save(peter); when() .get(String.format("http://localhost:%s/hello/Pan", port)) .then() .statusCode(is(200)) .body(containsString("Hello Peter Pan!")); } }
同样,我们使用@SpringBootTest启动整个Spring应用程序。在本例中,我们@Autowire PersonRepository,这样我们就可以轻松地将测试数据写入数据库。当我们现在要求REST API向我们的朋友“Pan先生”说“hello”时,我们得到了一个很好的问候。神奇的!如果您甚至不使用web接口,那么端到端测试就足够了。
验收测试——您的特性工作正常吗?
您在测试金字塔中的位置越高,就越有可能从用户的角度测试您正在构建的特性是否正确工作。您可以将您的应用程序视为一个黑盒子,并将测试中的焦点从
when I enter the values
x
andy
, the return value should bez
towards
given there's a logged in user
and there's an article "bicycle"
when the user navigates to the "bicycle" article's detail page
and clicks the "add to basket" button
then the article "bicycle" should be in their shopping basket
有时您会听到这类测试的术语功能测试或验收测试。有时候人们会告诉你功能测试和验收测试是两码事。有时这些术语会被合并。有时人们会无休止地争论措辞和定义。这种讨论通常会引起很大的困惑。
事情是这样的:在某一点上,您应该确保从用户的角度测试您的软件是否正确工作,而不仅仅是从技术的角度。你所谓的测试其实并不那么重要。然而,进行这些测试是必要的。选择一个术语,坚持它,并编写这些测试。
这也是人们谈论BDD和允许您以BDD方式实现测试的工具的时刻。编写测试的BDD或BDD风格的方法是一个很好的技巧,可以将您的思维从实现细节转移到用户的需求。去试试吧。
您甚至不需要采用成熟的BDD工具,比如Cucumber(尽管您可以)。一些断言库(如cai .js)允许您使用should风格的关键字编写断言,从而使您的测试读起来更像北斗。即使您不使用提供这种表示法的库,聪明且经过良好分解的代码也将允许您编写关注用户行为的测试。一些辅助方法/函数可以让你走很长的路:
# a sample acceptance test in Python def test_add_to_basket(): # given user = a_user_with_empty_basket() user.login() bicycle = article(name="bicycle", price=100) # when article_page.add_to_.basket(bicycle) # then assert user.basket.contains(bicycle)
验收测试可以有不同的粒度级别。大多数情况下,它们将相当高级,并通过用户界面测试您的服务。但是,最好理解在技术上没有必要在测试金字塔的最高级别上编写验收测试。如果您手头的应用程序设计和场景允许您在较低的级别上编写验收测试,那么就去做吧。进行低级测试比进行高级测试要好。验收测试的概念—证明您的特性为用户正确工作—与您的测试金字塔完全正交。
探索性测试
即使是最勤奋的测试自动化工作也不是完美的。有时您会在自动化测试中遗漏某些边缘情况。有时候,通过编写单元测试几乎不可能检测到特定的bug。某些质量问题甚至不会在您的自动化测试中变得明显(考虑设计或可用性)。尽管您对测试自动化的意图是最好的,但是某些类型的手工测试仍然是一个好主意。
图12:使用探索性测试来发现构建管道没有发现的所有质量问题
在您的测试组合中包括探索性测试。它是一种手工测试方法,强调测试人员发现运行系统中的质量问题的自由和创造性。只需在常规的时间表上花些时间,卷起袖子,试着打破你的应用程序。使用一种破坏性的思维方式,想出一些方法来引发应用程序中的问题和错误。记录下你找到的所有东西。注意bug、设计问题、慢响应时间、丢失或误导错误消息,以及所有其他可能会惹恼您的软件用户的事情。
好消息是,您可以愉快地使用自动化测试自动化您的大部分发现。为您发现的bug编写自动化测试可以确保将来不会出现任何bug的回归。此外,它还可以帮助您在修复bug期间缩小问题的根源。
在探索性测试期间,您将发现在构建管道中未被注意到的问题。不要沮丧。这是关于构建管道成熟度的重要反馈。和任何反馈一样,一定要付诸行动:想想你能做些什么来避免未来出现这类问题。也许您错过了一组特定的自动化测试。也许您只是在这个迭代中草率地使用了自动化测试,并且需要在将来进行更彻底的测试。也许有一个闪亮的新工具或方法,您可以在您的管道中使用,以避免这些问题在未来。一定要采取行动,这样您的管道和整个软件交付就会随着时间的推移而变得更加成熟。
测试术语的混淆
讨论不同的测试分类总是困难的。我所说的单元测试可能与您的理解略有不同。而集成测试则更糟。对某些人来说,集成测试是一项非常广泛的活动,它通过整个系统的许多不同部分进行测试。对我来说,这是一件相当狭隘的事情,一次只测试一个外部部分的集成。有些将它们称为集成测试,有些将它们称为组件测试,有些更喜欢使用服务测试这个术语。甚至有人会说,这三个词完全是两码事。没有对错之分。软件开发社区还没有设法解决围绕测试的定义良好的术语。
不要太拘泥于模棱两可的术语。无论您将其称为端到端测试、宽堆栈测试还是功能测试,都没有关系。您的集成测试对您和其他公司的人是否有不同的意义并不重要。是的,如果我们的专业能在一些定义明确的术语上达成一致并坚持下去,那就太好了。不幸的是,这还没有发生。由于在编写测试时存在许多细微差别,所以它实际上更像是一个频谱,而不是一堆离散的桶,这使得一致的命名更加困难。
重要的是,您应该找到适合您和您的团队的术语。要清楚要编写的不同类型的测试。在您的团队中就命名达成一致,并就每种测试类型的范围达成一致。如果你在你的团队中(甚至在你的组织中)保持这种一致性,这才是你真正应该关心的。Simon Stewart在描述谷歌使用的方法时很好地总结了这一点。我认为这很好地说明了过多地关注名称和命名约定是不值得这么麻烦的。
将测试放入部署管道中
如果您正在使用持续集成或持续交付,那么您将拥有一个部署管道,它将在您每次对软件进行更改时运行自动化测试。通常,这个管道被分成几个阶段,这些阶段会逐渐让您更加确信您的软件已经准备好部署到生产环境中。听到所有这些不同类型的测试,您可能想知道应该如何将它们放置在部署管道中。要回答这个问题,您只需要考虑持续交付的一个非常基本的价值(实际上是极限编程和敏捷软件开发的核心价值之一):快速反馈。
一个好的构建管道会告诉您,您已经尽可能快地搞砸了。您不希望仅仅等待一个小时就发现您最新的更改破坏了一些简单的单元测试。如果你的管道花了那么长时间给你反馈,你很可能已经回家了。通过将快速运行的测试放在管道的早期阶段,您可以在几秒钟内,甚至几分钟内获得这些信息。相反,您将较长时间运行的测试(通常是范围更广的测试)放在后面的阶段,以避免延迟来自快速运行测试的反馈。您可以看到,定义部署管道的阶段不是由测试类型驱动的,而是由测试的速度和范围驱动的。记住,它可以是一个非常合理的决定的范围较窄,湍急的集成测试在同一阶段作为单元测试-仅仅是因为他们给你更快的反馈,而不是因为你想画线测试的正式类型。
避免重复测试
既然您已经知道应该编写不同类型的测试,那么还有一个需要避免的陷阱:在金字塔的不同层中复制测试。虽然你的直觉可能会说没有太多的测试,但我向你保证,确实有。您测试套件中的每一个测试都是额外的负担,并不是免费的。编写和维护测试需要时间。阅读和理解他人的测试需要时间。当然,运行测试需要时间。
与生产代码一样,您应该力求简单并避免重复。在实现测试金字塔的过程中,你应该记住两条经验法则:
- 如果高级测试发现错误,并且没有低级测试失败,则需要编写低级测试
- 把你的测试尽可能往下推
第一个规则很重要,因为较低级别的测试允许您更好地缩小错误范围,并以独立的方式复制它们。当您调试手头的问题时,它们将运行得更快,并且不会那么臃肿。它们将成为未来很好的回归测试。第二条规则对于保持测试套件的速度非常重要。如果您已经在较低级别的测试中自信地测试了所有条件,那么没有必要在您的测试套件中保留较高级别的测试。它只是没有增加更多的信心,一切都在工作。在日常工作中进行冗余的测试会变得很烦人。您的测试套件将变慢,当您更改代码的行为时,您需要更改更多的测试。
让我们换一种说法:如果更高级别的测试让您对应用程序的正确工作更有信心,那么您应该拥有它。为控制器类编写单元测试有助于测试控制器本身中的逻辑。不过,这并不能告诉您这个控制器提供的REST端点是否实际响应HTTP请求。因此,您向上移动测试金字塔,并添加一个测试来精确地检查它——但仅此而已。您不需要再次测试低级测试中已经包含的所有条件逻辑和边缘用例。确保高级测试集中于低级测试不能覆盖的部分。
当涉及到消除没有任何价值的测试时,我是严格的。我删除已经在较低级别上覆盖的高级测试(假定它们不提供额外的价值)。如果可能的话,我用较低级别的测试替换较高级别的测试。有时候这很难,尤其是当你知道做一个测试是件很辛苦的事情的时候。小心沉没成本谬论,按下删除键。没有理由在没有价值的测试上浪费更多宝贵的时间。
编写干净的测试代码
与编写一般代码一样,编写好的、干净的测试代码需要非常小心。这里有更多的提示,让你在使用你的自动化测试套件之前,可以使用可维护的测试代码:
测试代码和生产代码一样重要。给予同样的关心和关注。“这只是测试代码”并不是为草率的代码辩解的有效借口
每个测试测试一个条件。这有助于你保持你的测试简短和容易推理
“安排、执行、断言”或“给定、何时、然后”是保持测试结构良好的很好的助记符
可读性很重要。不要太干。如果可以提高可读性,复制是可以的。试着在干燥和潮湿的代码之间找到一个平衡
当有疑问时,使用三原则来决定何时重构。使用之前重用
结论
就是这样!我知道这是一个漫长而艰难的阅读来解释为什么以及如何测试你的软件。好消息是,这些信息是非常永恒的,并且与您正在构建的软件类型无关。无论您是在开发微服务、物联网设备、移动应用程序还是web应用程序,本文的经验教训都可以应用到所有这些方面。
我希望本文能对您有所帮助。现在继续检查示例代码,并将这里解释的一些概念放入您的测试组合中。拥有一个可靠的测试组合需要一些努力。相信我,从长远来看,这样做是有回报的,它会让你作为一个开发者的生活更加平静。
确认
感谢Clare Sudbery、Chris Ford、Martha Rohte、Andrew Jones-Weiss David Swallow、Aiko Klostermann、Bastian Stein、Sebastian Roidl和Birgitta Bockeler为本文的早期草稿提供反馈和建议。感谢Martin Fowler的建议、见解和支持。
原文:https://martinfowler.com/articles/practical-test-pyramid.html
本文:http://pub.intelligentx.net/node/512
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 63 次浏览
【软件测试】快速软件测试方法
我称之为快速软件测试。
我们为什么要测试?我们测试以全面了解产品及其周围的风险。我们进行测试以发现威胁产品价值的问题,或者威胁按时,成功完成任何类型的开发工作的问题。我们进行测试以帮助业务,经理和开发人员确定他们所拥有的产品是否是他们想要的产品。
最重要的是,我们测试是因为它是负责任的事情。我们有责任关心我们的团队,组织,客户和社会。发布经过严格测试的软件将违反该义务。
快速软件测试(RST)就是这样。它是一种负责任的软件测试方法,以测试人员和需要测试的人为中心。它是一种方法(在“方法系统”的意义上)包含工具(又名“自动化”),但强调指导和推动过程的熟练技术人员的作用。
这种方法的本质在于它的本体论(我们如何组织和定义各种优先级,想法,活动和其他测试要素),人文主义(我们通过将方法置于每个从业者的控制下来培养责任和应对能力),以及启发式(解决问题的错误方法)。
RST不是一组模板和规则,而是一种心态和技能。这是了解测试的一种方式;这是测试人员知道如何做的一系列事情。
我的意思是迅速
我不是在谈论打字或点击更快。我说的是更好的测试策略。这基本上意味着九件事:
- 掌控自己的工作。除非您受到对您的工作负责的人的直接监督,否则您不得盲目地遵循任何指示或过程。这意味着您使用的任何实践,无论您如何与项目中的其他流程协调,请自行决定。不要将测试基于您不理解的测试用例。如果您不了解某些事情,请在研究之前研究它,停止这样做,或者建议您的客户盲目地工作。
- 停止做有帮助的事情。很难说哪些活动真的是浪费时间而哪些不是浪费时间,但这是一条黄金法则:如果你认为自己在做一些浪费时间的事情,就不要再做了。
- 拥抱探索和实验。快速做好测试的一部分是快速了解产品,这不仅仅需要阅读规范或重新利用旧的测试用例。您必须潜入并与产品互动。这有助于您更快地建立它的心理模型。
- 专注于产品风险。一种尺寸的测试并不适合所有人。在需要的地方进行更深入的测试,并在潜在的产品风险较低时进行浅层测试或根本不进行测试。
- 使用轻量级,灵活的启发式方法来指导您的工作。 RST方法包括许多旨在帮助构建您的工作的启发式模型。这些模型简洁明了,可用于支持从自发和非正式测试到审议和正式测试的任何级别的测试。它们始终在您的控制之下。
- 使用解决问题的最简洁的文档形式。文档可能会对任何项目造成巨大拖累。它很难创建并且难以维护。要么避免它,要么使用最轻的形式的文档来传达需要它的特定人员所需要的东西。
- 使用工具加速工作。测试人员不一定需要编写代码,但他们确实需要强大的工具。无论您是自己创建工具还是寻求其他人的帮助,您都可以将工具(包括自动检查)应用于测试过程的所有方面
- 解释你的测试及其价值。当您能够以注重价值的方式清晰快速地解释测试的重要性时,您的客户和团队成员将会感觉到您的时间得到充分利用,因此足够快。
- 提高您的技能,以便您可以完成上述所有工作。我们不提供可以吞咽的药丸,让您可以做这些事情。但我们确实向您展示了如何发展您的技能,以及如何发展它们。通过培养判断力和对不同技术,工具和流程的广泛了解,您可以选择一种快速的测试方法来满足所有业务需求。
想了解详情?
以下是RST的许多元素的路线图:
可以在此处找到一些表达RST的参考文档。
RST的基础是什么?
RST受到Gerald M. Weinberg,Cem Kaner和Billy Vaughan Koen,以及社会学家Harry Collins,家庭治疗师Virginia Satir以及诺贝尔奖获得者Herbert Simon,Richard Feynman,工作和科学方法的强烈影响。和Daniel Kahneman。如果您钦佩他们的工作,您会发现很多因我们提供的方法和课堂体验而产生共鸣。
RST还基于Cem Kaner,James Bach和Bret Pettichord的“软件测试经验教训:上下文驱动的方法”并与之相关。以及我的书“海盗 - 学者的秘密”中描述的自我教育和独立思考的生活方式。
以下是RST的具体前提,由我和Michael Bolton撰写。方法论中的所有内容都以某种方式来自这个基础。这些前提来自我几十年的经验,研究和讨论。
- 软件项目和产品是人与人之间的关系,人是情感和理性思想的生物。是的,还有技术,物理和逻辑元素,这些元素非常重要。但软件开发主要受人类方面的影响:政治,情感,心理,感知和认知。项目经理可以声明任何给定的技术问题对于企业来说根本不是问题。用户可能需要他们永远不会使用的功能。你的神奇工作可能会被拒绝,因为程序员不喜欢你。新手用户的足够快的性能对于有经验的用户来说可能是不可接受的。对于重要的人来说,质量始终是有价值的。产品质量是产品与人之间的关系,绝不是可以与人类环境隔离的属性。
- 每个项目都在不确定和时间压力的条件下进行。某些程度的混乱,复杂性,波动性和紧迫性困扰着每个项目。混乱可能是瘫痪,复杂性压倒性,波动性令人震惊,紧迫性迫在眉睫。原因很简单:新颖,雄心和经济。每个软件项目都试图生成新的东西,以解决问题。软件开发人员渴望解决这些问题。与此同时,他们经常尝试做的事情远远超过他们所拥有的资源。这不是人类的任何道德错误。相反,它是演化理论所谓的“红皇后”效应的结果:你必须尽可能快地跑到同一个地方。如果您的组织没有承担风险,您的竞争对手将 - 并最终您将为他们工作,或根本不工作。
- 尽管我们有最好的希望和意图,但某种程度的缺乏经验,粗心大意和无能是正常的。这个前提很容易验证。首先要诚实地看待自己。您是否拥有在不熟悉的领域或不熟悉的产品中工作所需的所有知识和经验?你有没有犯过你没有抓到的拼写错误?您仔细阅读了哪些测试教科书?你有多少学术论文?您是否熟悉集合论,图论和组合学?你是否精通至少一种编程语言?您现在可以坐下来使用de Bruijn序列来优化您的测试数据吗?你知道什么时候避免使用它吗?您是否完全熟悉所测试产品中使用的所有技术?可能不 - 而且没关系。创新的软件开发工作的本质是扩展即使是最有能力的人的极限。其他方法似乎假设每个人都能够并且将会在正确的时间做正确的事情。我们发现这令人难以置信。任何忽视人类易犯错误的方法都是幻想。通过说人类的错误是正常的,我们不是试图为它辩护或为它道歉,但我们指出,我们必须期望在我们自己和其他人中遇到它,以富有同情心的方式处理它,并充分利用它我们学习手艺和建立技能的机会。
- 测试是一项活动;它是性能,而不是工件。大多数测试人员会随便说他们“编写测试”或者他们“创建测试用例。”这很好,就目前而言。这意味着他们构思了想法,数据,程序,以及可能使某项任务或其他任务自动化的程序;他们可能已经用书面或程序代码表达了这些想法。当任何这些事物与它们所代表的想法混淆时,以及当表示与实际测试产品混淆时,就会出现问题。这是一种称为物化的谬误,即将抽象视为事物的错误。在某个测试人员使用该产品之前,观察并解释这些观察结果,没有进行任何测试。即使您编写了一个完全自动的检查流程,该流程的结果也必须由负责人审核和解释。
- 测试的目的是发现产品的状态及其价值的任何威胁,以便我们的客户能够做出明智的决策。当人们使用“测试”这个词时,会有其他目的。对于某些人来说,测试可能是检查基本功能似乎有效的一种仪式。这不是我们的观点。我们正在寻找重要的问题。我们寻求对产品的全面了解。我们这样做是为了满足客户的需求,无论他们是谁。为客户服务所需的测试水平会有所不同。在某些情况下,测试将更加正式和简单,在其他情况下,非正式和精细。在所有情况下,测试人员都必须向那些必须对其做出决策的人提供有关产品的重要信息。测试人员照亮了路。
- 我们承诺进行可信的,具有成本效益的测试,并且我们将告知客户任何威胁该承诺的事情。 Rapid Testing寻求完全满足测试任务的最快,最便宜的测试。当10美元的测试能够完成这项工作时,我们不应该建议进行百万美元的测试。我们测试得还不够;鉴于项目的局限性,我们必须进行良好的测试。此外,当我们受到一些可能妨碍我们做好工作的约束时,测试人员必须与客户合作解决这些问题。无论我们做什么,我们都必须准备好证明和解释它。
- 我们不会故意或疏忽地误导我们的客户和同事。这种道德前提推动了快速软件测试的许多结构。测试人员经常成为客户善意但无理或无知的要求的目标。我们可能会被要求压制坏消息,创建我们无意使用的测试文档,或者生成无效指标来衡量进度。我们必须礼貌而坚决地抵制这些要求,除非我们认为它们符合我们客户的更好利益。至少我们必须告知客户任何阻碍我们测试的任务或工作模式的影响,或者造成测试的错误印象。
- 尽管测试人员无法控制产品的质量,但他们对工作质量负责。测试需要许多互锁技能。测试是一项工程活动,需要大量的设计工作来构思和执行。像许多其他高度认知的工作一样,例如调查报告,驾驶飞机或编程,对于没有实际工作的人来说很难有效地监督它。因此,测试人员不得放弃对自己工作的责任。出于同样的原因,我们不能对产品本身的质量承担责任,因为它不在我们的控制范围内。只有程序员和他们的管理层才能控制。有时测试称为“质量保证”。如果是这样,请将其视为质量协助,而非质量保证。
RST的演变
快速软件测试的起源是我在Apple Computer和Borland International运行测试团队的经历,可以追溯到1987年。我一直在寻找测试的本质,而不是在当时的任何标准或书籍中找到它。然后我收到了Ed Yourdon,Tom DeMarco,Tim Lister和Jerry Weinberg的重要线索。他们促使我考虑一般系统思考。他们开始思考心理学在工程学中的关键作用。然后在90年代中期,在旧金山举行的测试会议上进行的通宵谈话中,Cem Kaner敦促我探索认知心理学和认识论。这些领域提供了我新兴方法的组织框架。
我曾经给出的关于测试方法的第一次谈话叫做动态软件质量保证。我是在1990年为Apple大学做过的。我希望我还有那个录像带。这是我最后一次没有留胡子的视频。我在谈论启发式和系统思考,但我认为我不知道这些话。
我在1993年举行的第一次重要的会议讨论叫做“持久性特别测试”。我在谈论探索性测试的非凡价值,尽管我不会在今年晚些时候开始使用该术语。
我的测试方法的第一个公开版本体现在1995年的一个名为市场驱动的软件测试的类中。然后我创建了一个基于风险的测试课程,以及业界第一个探索性测试课程。 2001年,我将这些课程结合起来,开始将该方法正式化,将课程重命名为Rapid Software Testing。
2004年,Michael Bolton将他作为开发人员,测试人员,文档管理员和项目经理的经验带到课堂上,添加了新的练习,谜题和主题。 Michael在商业和金融服务软件方面的工作增加并影响了关于形式和文档角色的想法,并于2006年成为该课程和方法的共同作者。多年来,他帮助改进了RST,提高了词汇量,并在检查 - 原则上可以由机械完成的测试的一部分 - 和测试之间引入了至关重要的区别 - 这需要测试人员的明确和隐性知识。
Paul Holland(来自嵌入式系统和电信),Huib Schoots(金融服务)和Griffin Jones(医疗设备和其他监管领域)各自将他们的想法,经验和教学方式融入其中。 我们的每位教师都受益于其他人的工作,每个人都教授自己的个人RST变体。
RST历来专注于测试和测试人员。 但是我们最近重新调整了一点,因为许多进行测试的人要么没有被称为测试人员,要么除了测试之外还做其他事情。 如今,我们的客户需要了解RST如何与Agile和DevOps集成。
这是我们的敏捷快速测试网格,它可以帮助我们解释:
方法与什么兼容
RST是一种上下文驱动的方法。这意味着我们的课程不是专门针对敏捷,DevOps,精益,瀑布或受监管环境中的测试;它也不包含您可能用于模拟用户或支持任何其他测试方面的任何特定测试工具。但是,我们通过让您控制流程来帮助您将这些内容应用于测试,以便您解决实际存在于您的上下文中的问题。
关键问题是责任。作为测试人员,责任意味着做出独立的专业判断,以应用实践和工具来发现您特定项目的每个重要问题。责任意味着在项目和产品风险需要时进行深度测试。负责任地应用诸如“单元测试”或“行为驱动的开发”之类的实践意味着在适合您的环境时选择它,而不是因为您听说Facebook和Google这样做,或者因为您被命令这样做。负责任地使用自动化包括在更有效,更高效或解决自动化忽略的问题时考虑自动化之外的方法。责任意味着当你说“可能什么都不会出错”时,你不仅仅是在猜测。
RST不告诉你该怎么做。相反,它是一个负责任和有文化地考虑做什么的框架。 RST的教师具有广泛的环境经验,可以帮助您定制材料以满足您的需求。因此,我们有很多关于如何将自动化应用于测试,或如何在文档密集型项目中进行良好测试的想法。
有一点特别是RST方法与以下方面不兼容:假测试。是的,有些组织有目的地最大限度地利用文书工作,并鼓励他们知道很少发现错误的浅层测试脚本。 “工厂式”测试通常相当于假测试,因为它看起来很合理,尽管未达到其明显的目的。一些公司 - 大型测试外包公司因此而闻名 - 甚至这是一种商业模式,可以最大化计费时间。这些公司不希望更有效地进行测试,因为这会减少他们的计费时间。他们希望对那些不了解深度测试的人看起来很有成效。如果您为这样的公司工作,如果您参加RST课程,您的老板会非常恼火。它会让你提出不舒服的问题。
以下是有关RST如何与其他一些流行的测试方法进行比较的其他详细信息。
原文:https://www.satisfice.com/rapid-testing-methodology
讨论: 知识星球【数字化和智能转型】
- 37 次浏览
【软件测试】用于衡量质量保证成功的64项基本测试指标
软件测试指标是衡量和监控测试活动的一种方法。 更重要的是,它们可以深入了解您的团队的测试进度,生产力和被测系统的质量。 当我们问自己“我们测试了什么?”时,指标会给我们提供更好的答案,而不仅仅是“我们已经测试过。”不同的团队根据他们想要跟踪和控制或改进的内容来衡量各个方面。
度量通常基于数据组合传达结果或预测。
结果指标:
指标主要是完成的活动/流程的绝对指标。
示例:在套件中运行一组测试用例所花费的时间
预测指标:
作为衍生工具的指标,并作为不利结果的早期预警信号。
示例:创建的缺陷与已解决的图表显示缺陷修复率。如果此速率低于所需速率,则会引起团队注意。
为何选择测试指标?你为什么要关心?
收集测试指标的目的是使用数据来改进测试过程,而不是仅显示花哨的报告。这包括找到问题的切实答案:
- 测试需要多长时间?
- 测试需要多少钱?
- 虫子有多糟糕?
- 发现了多少个错误?重新打开?关闭?延期?
- 测试团队找不到多少错误?
- 测试了多少软件?
- 测试会按时完成吗?软件可以按时发货吗?
- 测试有多好?我们使用的是低价值的测试用例吗?
- 测试成本是多少?
- 测试工作是否足够?我们可以在此版本中进行更多测试吗?
这些问题的好答案需要衡量。这篇文章包括测试人员和QA经理最常使用的64个绝对,衍生,结果和预测指标。
基本指标
作为测试人员,您的指标创建之路必须从某个地方开始。基本QA指标是绝对数字的组合,然后可用于生成衍生指标。
绝对数字
-
测试用例总数
-
通过的测试用例数
-
测试用例数失败
-
被阻止的测试用例数
-
发现的缺陷数量
-
接受的缺陷数量
-
拒绝的缺陷数量
-
延迟的缺陷数量
-
关键缺陷的数量
-
计划的考试时数
-
实际测试小时数
-
发货后发现的错误数量
衍生指标
绝对数字是一个很好的起点,但通常只有它们是不够的。
例如,如果您报告跟随网格,这可能不足以理解我们是否按计划完成,或者我们应该每天查看的结果。
Day | Day 1 | Day 2 | Day 3 |
Results Completed | 35 | 40 | 45 |
在这种情况下,绝对数字产生的问题多于答案。 借助衍生指标,我们可以深入探讨如何解决测试过程中的问题。
测试跟踪和效率
以下是有助于测试跟踪和效率的派生指标:
13. | |
14. | |
15. | |
16. | |
17. | |
18. | |
19. | |
20. | |
21. |
测试努力
测试工作指标将回答有关您的测试工作的“多长时间,多少次以及多少”的问题。 这些指标非常适合为将来的测试计划建立基线。 但是,您需要记住这些指标是平均值。 一半的价值落在平均值上,其中一半价格低于平均值。
一些具体措施是:
22. | |
23. | |
24. | |
25. | |
26. | |
27. |
测试有效性
测试有效性答案,“测试有多好?”或“我们是否运行高价值测试用例?”它是测试集的错误发现能力和质量的衡量标准。 测试有效性指标通常显示测试团队发现的缺陷数量与软件发现的整体缺陷之间的差异百分比值。
28. 基于度量:使用缺陷遏制效率的测试有效性
测试有效性百分比越高,测试集越好,长期测试用例维护工作量就越少。
示例:如果一个版本的测试有效性为80%,则意味着20%的缺陷从测试团队中脱离出来。
- 该数字应导致对改进测试集的调查,回顾和纠正措施,从而增加测试集的缺陷识别率。
- 测试有效性永远不会是100%。因此,团队应该瞄准更高的价值,如果不是100,不应该失望。
- 平均有效率超过版本将显示测试集改进的努力是否给出了积极的结果。
29.基于情境:使用团队评估测试有效性
在以下情况下使用缺陷控制效率指标可能不起作用
- 该产品已经成熟
- 产品不稳定且有缺陷
- 由于时间/资源限制,未完成足够的测试
在这种情况下,我们需要另一种方法来衡量基于意见或背景的测试集有效性。
您可以要求您的团队对测试集的评分进行评分。在您这样做之前,告诉您的团队不偏不倚并定义一个好的测试集意味着什么是很重要的。例如,您的团队可能会认为一个好的测试集应该能够充分满足高风险要求。切合实际,专注于应用程序的最关键领域。
您的团队也可以使用主观缩放方法。在100%评级(1到10分)中,请您的团队给测试集评分,以确定测试集的完整性,最新性和有效性。获得平均得分,以获得团队感知的平均测试效果。从主题专家的角度谈论哪些测试的好与坏,证明是缩小测试重点的有意义的练习。
告诉您的团队不偏不倚并定义一个好的测试集意味着什么是很重要的。
测试覆盖率
软件质量指标衡量正在测试的应用程序的运行状况。不可避免的是,您要分析的下一个核心指标集围绕着覆盖范围。测试覆盖率指标衡量测试工作量并帮助回答“测试了多少应用程序?”
例如,“在这些通过或失败的测试中,我的应用程序的工件或区域是什么,它们旨在确保我的产品以高质量生产。”以下是一些关键的测试覆盖率指标。
30. |
这让我们了解了与未完成的测试运行相比所执行的总测试。 它通常以百分比值表示。
31. |
要获得有关测试覆盖范围的要求的高级视图,您只需要划分sprint,发布或项目的范围要求总数所涵盖的要求数量。
这通常只显示是否存在关联测试,而不是显示测试运行的结果。
32.按要求测试案例
最常见的方法是查看正在测试的功能,并查看我们与用户故事或要求一致的测试数量。
REQ | TC Name | Test Result |
REQ 1 | TC Name1 | Pass |
REQ 2 | TC Name2 | Failed |
REQ 3 | TC Name3 | Incomplete |
33.每项要求的缺陷(要求缺陷密度)
每个要求的缺陷密度有助于发现哪个要求比其他要求更具风险。 例如,测试用例可能没问题,但要求可能是造成所有问题的原因。
Req name | Total # of Defects |
Req A | 25 |
Req B | 2 |
34.没有测试范围的要求
重要的是要知道您是否已准备好通过适当的测试覆盖率将需求推向生产。
这表明哪些要求没有测试覆盖率以及需求处于什么阶段。例如,处于“完成”状态的要求比“待办事项”状态中的要求风险更大。
REQ ID | REQ NAME | REQ STATUS |
REQ001 | REQ A | To Do |
REQ002 | REQ B | Done |
尽管更高的测试覆盖率和图表可以增加对测试工作的信心,但它是一个相对值。就像我们找不到所有错误一样,我们无法创建足够的测试来实现100%的测试覆盖率。这不是测试人员的限制,而是由于所有系统都未绑定的现实。当我们考虑字段,功能和端到端测试级别时,有无数的测试。因此,最好确定将有资格作为100%测试覆盖率限定为有限的测试库存。
在WhiteBoard Friday视频系列中了解有关充分利用软件测试指标的更多提示:重要的指标。
测试经济学指标
人员(时间),基础设施和工具有助于降低测试成本。测试项目没有无限的货币资源可供支出。因此,重要的是要知道你打算花多少钱,以及你最终花多少钱在现实中。以下是一些测试经济学指标,可以帮助您当前和未来的预算计划。
35.测试的总分配成本
CIO和QA董事为单个项目或整年的所有测试活动和资源编制的预算金额
36.实际测试成本
进入测试的实际美元时间
计算此成本的一种方法是测量每个要求,每个测试用例或每个测试小时的测试成本。
例如,如果您的预算是1000美元并且包括测试100个要求,则测试要求的成本是1000/100 = 10美元。每个测试小时的成本,100小时1000美元意味着每小时10美元。当然,这假设所有要求在复杂性和可测试性方面都是相同的。
这些数字对于充当基线很重要,有助于估算项目的未来预算。
37.预算差异
实际成本与计划成本之间的差异
38.附表差异
完成测试的实际时间与计划时间之间的差异
如果实际成本低于分配预算(负差额),这对项目来说是个好消息。但是,这也可能意味着估计不正确。方差为零是优选的。
请阅读此处了解更多信息
39.每个bug修复的成本
这是通过每个开发人员在缺陷上花费的金额来计算的
如果开发人员花了10个小时来修复错误并且开发人员的每小时费用是60美元,那么错误修复的成本是10 * 60美元= 600美元。
有些团队还会考虑重新测试的成本,以获得更准确的测量结果。
40.不测试的成本
如果一组新功能投入生产但需要返工,那么返工所需的所有费用等于未测试的成本。
不测试的成本也可以追溯到更主观的价值,例如一个人的观点。以下是未测试的主观成本的一些示例:
- 更多客户服务电话/服务请求
- 生产性停电
- 失去用户/客户信任等
- 失去客户忠诚度
- 品牌知名度不高
测试团队指标
这些指标可用于了解每个测试团队成员的工作分配是否统一,以及是否有任何团队成员需要更多的流程/项目知识说明。永远不应该使用这些指标来归咎于责备,而应该帮助知识共享,而不应该用它来归咎于责备。
41.返回缺陷的分布,团队成员明智 - 见解2.0
42. 每个测试团队成员重新测试的开放缺陷的分布 - 洞察力2.0
通常,饼图或直方图用于快速获取工作分配的快照。 下面的图表立即引起我们的注意,鲍勃超额预订,大卫未得到充分利用。 这使测试主管/经理有机会研究为什么会这样,并在需要时采取纠正措施。
测试执行状态
测试执行快照图表显示组织为已通过,失败,阻止,未完成和未执行的总执行次数,以便轻松吸收测试运行状态。 这些图表是日常状态会议的绝佳视觉辅助工具,因为原始数字有更高的机会滑落人们的思维。 不断增长和萎缩的酒吧吸引了人们的注意力,更有效地传达了进步和速度。
45.测试执行状态图表
测试执行/缺陷查找率跟踪
这些图表有助于理解测试速率和缺陷发现率与期望值的比较。
取累积缺陷计数和测试执行率,绘制理论曲线。 与实际值相比,这将触发早期的红色标记,如果要达到目标,测试过程需要更改。
46.测试执行跟踪和缺陷查找速率跟踪
更多信息和图片来源:
https://www.stickyminds.com/sites/default/files/presentation/file/2013/06STRER_…
变更指标的有效性
软件经历了变化 - 频繁,极少,远在中间。必须监控所包含的变更,以了解它们对现有系统稳定性的影响。变化通常会导致新的缺陷,降低应用稳定性,导致时间线滑落,危及质量等。
这些措施可以帮助我们更好地了解影
47.测试变化的影响
可归因于更改的缺陷总数。这可能意味着确保缺陷得到适当影响,并在向开发报告时附加固定视觉。将这些缺陷归类为变更相关与否,这是一种努力,但这是值得的。
48.缺陷注射率
可归因于更改的已测试更改/问题的数量
例如:如果对系统进行了10次更改,并且30个缺陷可归因于更改,则每次更改最终会注入三个缺陷,并且每次更改的缺陷注入率为3。
知道这个数字将有助于预测每次新变化可能出现的缺陷数量。这允许测试团队战略性地使用回顾会议来了解他们帮助识别和修复来自新变更的缺陷的能力。
缺陷分布图
缺陷可以根据类型,根本原因,严重程度,优先级,模块/组件/功能区域,平台/环境,负责测试人员,测试类型等进行分类。您团队的权利如何设置完整的精细分类列表用于缺陷报告。
缺陷分布图有助于理解分布并确定目标区域以最大程度地去除缺陷。通过使用直方图,饼图或帕累托图表来显示开发和测试工作的位置。
49.由于原因导致的缺陷分布
50.模块/功能区域的缺陷分布
51.严重程度的缺陷分发
52.按优先顺序分配的缺陷
53.按类型分发缺陷
54.测试人员(或测试人员类型)的缺陷分布 - Dev,QA,UAT或最终用户
55.按测试类型分发缺陷 - 审查,演练,测试执行,探索等。
56.平台/环境的缺陷分发
直方图或饼图显示对高度受影响区域的即时视觉识别。但是,当参数太多而没有难以辨别的模式时,您可能必须使用帕累托图。缺陷
分配饼图:
这仅用于一个目的。它可以帮助您快速找到最密集的区域(大多数缺陷的原因)。
缺陷分布直方图:
创建直方图时,请务必将数据值从高到低或从低到高组织起来以产生最大影响。
您可以在此处停止,但要从指标中获得更多信息,请继续执行下一步。
将直方图与每个原因中的缺陷严重性分布相结合。 这将为您提供您应该更准确地关注的领域。
例如:我们知道造成大多数缺陷的区域是用户数据输入,但仅仅因为计数很高,我们不必首先关注那个,因为大多数“用户数据输入”都很低(绿色)。 缺陷数量最多且严重问题较多的下一类是“代码错误”。 因此,此图表将改进我们的数据,并让我们更深入地了解在何处引导进一步开发和修复工作。
缺陷分布帕累托图:
您还可以创建一个帕累托图表来查找哪些原因可以解决大多数缺陷。 在大多数情况下,可能不需要帕累托图。 但是,如果原因太多而且直方图或饼图不足以清楚地显示趋势,那么帕累托图可以派上用场。
要知道要关注哪些原因以便以最少的工作来修复最大缺陷(或者20%的原因可以修复80%的缺陷),在辅助轴上绘制一条80%标记的线并将其放到 X轴,如下:
导致用户数据输入和代码错误的原因应该比其他更重要。
随着时间的推移缺陷分布图表
测试周期结束时或测试周期中某一点的缺陷分布是该时间点缺陷数据的快照。如果事情变得更好或更糟,它不能用于得出结论。例如:在某个时间点,您将知道X个严重错误。我们不知道X是否超过最后一个周期或更少或相同。
随着时间的推移,您将了解每个类别中的缺陷。我们可以看到缺陷是否随着时间的推移或过度释放而增加,减少或稳定。
随时间的缺陷分布是多线图,显示一段时间内每个原因/模块/严重性趋势的缺陷。
57.原因导致的缺陷分布
58.模块随时间的缺陷分布
59.严重程度随时间的缺陷分布
60.平台随时间的缺陷分布
对于以下数据:
Test Cycle | Code Error | Security Problem(access permissions) | User error(data entry) |
Cycle 1 | 8 | 4 | 15 |
Cycle 2 | 7 | 3 | 13 |
Cycle 3 | 1 | 5 | 9 |
Cycle 4 | 1 | 5 | 4 |
Cycle 5 | 0 | 4 | 1 |
在5个周期内绘制3个原因的多线图,如下所示:
以下是图表可以帮助我们理解的内容:
- 最初的两个周期中的代码错误一直很高,但是从第3周期开始显着下降并保持低水平。这表明开发工作的有效性。
- 用户数据输入错误已从初始版本中暴露出来;这表明用户对产品的熟悉程度和接受度增加
- 随着测试周期的进行,安全相关的缺陷保持稳定并且没有改善(即数量减少)。这意味着,这些必须作为优先事项处理和处理。
限制:
- 对于负趋势,即对于发布/测试周期,如果缺陷计数在特定原因类别中增加,则此图表告诉我们这是什么,但不告诉我们原因。
- 当工作原因很少时,它是最有效的。想象一下,这个图表有10个原因类别,而不是3个,这将是太多的线条使它太繁忙和难以解释。
创建缺陷与缺陷已解决图表
61.缺陷创建与缺陷解决图表
找到的错误与固定图表相比,是一个缺陷分析折线图,可让我们查看缺陷删除过程模式并了解缺陷管理的有效性
要开始创建固定与发现图表,您必须先收集编号。发现的缺陷和没有。每天在测试周期中解决的缺陷。这是需要累积数字才有意义的图表之一。在10天的测试周期中考虑以下缺陷数据:
Test Cycle 1- Date | Bugs created | Bugs resolved | Cumulative bugs created(Total no. of bugs created so far) | Cumulative bugs resolved(Total number of bugs resolved so far) |
10/10/2016 | 6 | 4 | 6 | 4 |
10/11/2016 | 3 | 0 | 9 | 4 |
10/12/2016 | 4 | 4 | 13 | 8 |
10/13/2016 | 2 | 4 | 15 | 12 |
10/14/2016 | 2 | 3 | 17 | 15 |
10/15/2016 | 0 | 0 | 17 | 15 |
10/16/2016 | 1 | 0 | 18 | 15 |
10/17/2016 | 0 | 2 | 18 | 17 |
10/18/2016 | 0 | 2 | 18 | 19 |
10/19/2016 | 0 | 0 | 18 | 19 |
针对上述数据创建的缺陷与已解决的图表如下所示:
这张图很棒,但有太多的线条让我们分心。 因为创建和解决的错误的原始数量是没有意义的,您可以从图表中删除它们以获得更清晰的创建与已解决的图表,如下所示。
此图表回答了以下问题:
- 我们准备好了吗?
- 软件是否在测试结束时获得稳定性?
- 缺陷管理系统是否有效?
这是如何做:
- 1.在测试周期结束时,绿线变得更直,更平坦或更稳定 - 这表明错误发现率已经下降,累积错误数量不变 - 因此,它有助于我们回答问题 - “我们测试的足够吗? “或”产品是否已准备好发货?“
如果绿线越来越陡峭,这意味着即使在测试结束时,找到错误的速度也没有下降。因此,需要进行更多测试,产品尚未发货。
- 2.在曲线的末端,创建和解析的线会聚(或多或少)。这也是一个好兆头,因为它表明缺陷管理过程正在发挥作用并且正在有效地解决问题。
如果蓝线低于绿线,则意味着缺陷未及时解决,我们可能需要改进流程。
限制:虽然此图表回答了许多重要问题,但它确实有其局限性。
- 绿色线中的尖峰可能在测试周期开始时发生,此时错误发现率通常很高。当开发团队完成所有缺陷并将其中的大部分标记为已完成时,也可能出现蓝线尖峰。这可能会导致对正在发生的事情的一时的恐慌。
- 该图表显示了正在发生的事情,但需要进一步研究以了解“为什么”。
参考文献:
https://confluence.atlassian.com/jira064/created-vs-resolved-issues-rep…
管理测试过程 - 由雷克斯黑色。第4章“缺陷去除的进展情况”。
http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470404159.html
更多缺陷度量标准
62.缺陷去除效率/缺陷差距分析
缺陷删除效率是指开发团队能够处理和删除测试团队报告的有效缺陷的程度。
要计算缺陷差距,请计算提交给开发团队的总缺陷数以及在循环结束时修复的缺陷总数。使用公式计算快速百分比,
示例:在测试周期中,如果QA团队报告了100个缺陷,其中20个无效(不是错误,重复等),如果开发团队已经解决了其中的65个,则缺陷缺口%为:(65 / 100- 20)X100 = 81%(约)
在一段时间内收集数据时,缺陷差距分析也可以绘制为如下图形:
差距很大,表明开发过程需要改变。
更多信息:https://www.equinox.co.nz/blog/software-testing-metrics-defect-removal-efficien…
63.缺陷密度
缺陷密度定义为软件的软件或应用程序区域的每个大小的缺陷数。
如果测试周期结束时的缺陷总数为30,并且它们全部来自6个模块,则缺陷密度为5。
更多信息:http://www.softwaretestinghelp.com/defect-density/
64.缺陷年龄
缺陷年龄是一种衡量标准,可帮助我们跟踪开发团队开始修复缺陷并解决缺陷所需的平均时间。 缺陷年龄通常以单位天数来衡量,但对于每周或每天发布的快速部署模型团队,项目应以小时为单位进行衡量。
对于具有高效开发和测试流程的团队而言,低缺陷年龄标志着错误修复的更快转变。
缺陷年龄=创建时间差异和花费时间
了解如何使用qTest Insights 2.0在点播网络研讨会和幻灯片中分析软件质量,测试覆盖率和测试速度。
这篇文章由Swati Seela和Ryan Yackel撰写。
原文:https://www.qasymphony.com/blog/64-test-metrics/
- 339 次浏览
【软件测试】软件测试的未来:12测试专家分享他们的预测
你将学到什么
毫无疑问,软件测试领域目前正处于重大转型的中期。 软件在我们日常工作和个人生活中的普及对新软件提出了更高的期望,并迫使软件更快地推向市场。
因此,软件测试人员的角色也在发生变化,包括他们做什么,何时做以及与谁合作。 在自动化和人工智能无处不在的世界中,软件测试角色会变成什么样?
这本免费的20页指南采访了12位经验丰富的行业专家,分享他们对软件测试行业的预测并回答关键问题,例如:
- 软件测试领域的变化到底意味着什么?
- 软件测试人员如何为正在进行的转型做好准备?
- 拥抱新变化的最大挑战是什么?
- 领导人看到了哪些转变?
原文:https://www.qasymphony.com/landing-pages/future-software-testing-ebook/
讨论请加【数字化和智能转型】知识星球
- 23 次浏览
【软件测试】阳性与阴性与破坏性测试案例
视频号
微信公众号
知识星球
测试用例是一组条件或变量,测试人员将在这些条件或变量下确定应用程序、软件系统或网站是否符合规范并按预期运行。测试用例可以是肯定的,也可以是否定的,这意味着它测试的是正确的功能还是缺失的功能。
什么是测试用例?
测试用例是一组条件或变量,测试人员将在这些条件或变量下确定应用程序、软件系统或其功能之一是否正常工作。测试用例主要有三种类型:
- 阳性测试案例:在这些案例中,被测试的系统有望正常工作。这些测试旨在表明系统能够处理有效的输入并产生预期的输出。
- 阴性测试案例:这些是被测试系统预计会失败的案例。这些测试有助于确保系统能够优雅地处理无效输入,并在必要时产生错误消息或其他适当的输出。
- 破坏性测试案例:这些案例中,被测试的系统被故意破坏,以测试其恢复能力。这些测试有助于确保系统能够承受意外故障,并且仍然正常工作。
什么是阳性检测案例?
阳性测试用例是验证系统或应用程序在有效或预期输入条件下正确运行的能力的测试。
- 阳性测试案例的示例包括验证表单提交的正确数据输出、验证用户是否能够成功登录应用程序,或确认支付交易是否成功。
- 积极的测试用例对软件质量保证至关重要,有助于确保系统按预期运行,并在给出有效输入时产生正确的结果。
- 阳性测试用例用于评估系统或应用程序在给定有效输入或理想条件下的行为。
- 这些测试有助于确保应用程序按预期运行,并确保用户体验令人满意。
- 应该为应用程序的所有特性和功能编写阳性测试用例,并且应该包括边界值和边缘用例的测试用例。
- 阳性测试用例通常由对测试的应用程序或系统有深入了解的QA工程师或测试人员编写。
- 测试人员应该清楚地了解功能和期望的结果,并且应该熟悉应用程序的源代码和设计。
什么是阴性测试案例?
阴性测试用例用于测试系统的无效输入和意外行为。它们的设计目的是确保系统在给定无效或意外输入时按预期运行。
- 阴性测试案例很重要,因为它们可以发现错误,否则这些错误将无法被发现。
- 负测试用例是那些旨在证明系统在给定无效输入时不能按预期工作的测试。例如,登录系统的阴性测试用例可能输入了不正确的用户名和密码组合。这将确保系统不会对没有正确凭据的用户进行身份验证。
- 阴性测试用例也可以用于检查意外行为。例如,搜索引擎的否定测试用例可能是输入具有意外格式的查询。这将确保系统在给出意外输入时不会提供意外结果。
- 阴性测试用例对于确保系统安全也很重要。
- 它们可用于测试输入验证、身份验证、授权、访问控制和其他安全措施。例如,身份验证系统的阴性测试用例可能输入了无效的用户名或密码。这将确保系统不会对没有正确凭据的用户进行身份验证。
什么是破坏性测试案例?
破坏性测试用例是一种软件测试,旨在识别系统暴露在极端条件下时发生的软件故障。这些测试包括故意将系统置于异常或极端条件下,以确定其断裂点和造成的损坏程度。
- 破坏性测试的目的是在现场发生潜在的系统故障之前识别这些故障,并帮助确保系统能够承受这些条件。
- 破坏性测试可能涉及多种情况,例如故意引入不正确的数据,使系统过载,请求超过其处理能力,或者模拟可能导致硬件故障的极端温度。
- 这些测试旨在模拟真实世界的条件,并揭示系统中任何隐藏的弱点。这有助于在系统发布给用户之前识别和解决任何问题,确保产品更加可靠。
- 破坏性测试通常在受控环境中进行,在受控环境下可以密切监测测试条件,并可以快速将系统恢复到其原始状态。
- 这使得跟踪测试结果、识别任何问题和开发解决方案变得更加容易。
破坏性测试并不是软件测试的唯一类型。其他类型的软件测试包括功能测试、回归测试和性能测试。每种类型的软件测试都有自己的好处,可以与破坏性测试结合使用,以提供系统的全面视图。
阳性测试用例与阴性测试用例与破坏性测试用例
以下是阳性测试用例、阴性测试用例和破坏性测试用例之间的差异:
Factor | Positive Test Cases | Negative Test Cases | Destructive Test Cases |
---|---|---|---|
Functionality | Test cases that test the basic functionality of the software. | Test cases that test for errors or unexpected behavior. | Test cases that delete or modify data. |
Usability | Test cases that test for user-friendliness and easy navigation. | Test cases that test for confusing interfaces or difficult navigation. | Test cases that delete user data or preferences. |
Performance | Test cases that test for fast loading times and response times. | Test cases that test for slow loading times and response times. | Test cases that delete cached data or user preferences. |
Security | Test cases that test for proper authentication and authorization. | Test cases that test for vulnerabilities and exploits. | Test cases that delete user data or preferences. |
Design | Test cases are tests that are designed to ensure that a system works as expected. | Test cases are tests that are designed to ensure that a system does not work as expected. | Test cases are tests that are designed to deliberately break a system in order to test its robustness. |
Data | A positive test case is run on unaltered data | A negative test case is run on altered data | A destructive test case is run on permanently altered data. |
Example |
|
|
|
如何选择使用哪种类型的测试用例?
在决定使用哪种类型的测试用例时,需要考虑以下几个因素:
- 你测试的目的:如果你试图在你的软件中找到错误,那么你会想要使用阳性的测试用例。这些测试软件的预期行为。如果您试图了解软件在遇到意外输入时的反应,那么您将希望使用阴性测试用例。这些测试软件的意外行为。最后,如果您试图确定您的软件是否能够处理极端条件(如大量数据),那么您将希望使用破坏性测试用例。这些人故意试图破坏软件,看看它是如何响应的。
- 时间:正测试用例和负测试用例可以相对快速地编写,因为它们只需要几个不同的输入值。破坏性测试用例需要更长的时间来编写,因为它们必须非常具体和精心制作,才能有机会破坏软件。
- 成本:破坏性测试用例是迄今为止最昂贵的测试用例类型,因为它们通常需要专门的硬件和/或环境才能正常运行。阳性和阴性测试用例的成本要低得多,因为它们可以在没有特殊要求的任何系统上运行。考虑所有这些因素将帮助您决定哪种类型的测试用例适合您的需求。
- 38 次浏览
软件测试资料
实际软件工程中是否真的需要100%代码覆盖率(code coverage)?
https://www.zhihu.com/question/29528349
浅谈代码覆盖率
https://tech.youzan.com/code-coverage/
品质管理 如何量化测试覆盖率
https://testerhome.com/topics/10052
测试覆盖(率)到底有什么用?
https://www.infoq.cn/article/test-coverage-rate-role
64 Essential Testing Metrics for Measuring Quality Assurance Success
https://www.qasymphony.com/blog/64-test-metrics/
- 28 次浏览