什么是可维护性测试?
维护的主要定义是保持或维持特定状态的过程。软件的可维护性由开发人员负责,他们定期修改软件以满足不断变化的客户需求并解决客户提出的问题。
软件维护需要增强软件的功能,以包含客户需要的新功能,修改代码以避免将来出现问题,修复代码中的缺陷或错误,并确保不存在安全漏洞。此外,软件维护通常包括发布更新,以提高适应性和有效性,并替换不受欢迎的功能。
软件维护在很大程度上受到软件和代码质量的影响。质量较低的软件需要更多的维护。对于低质量软件,增加新需求或扩展现有代码的工作量和成本要高得多。
随着可维护性的提高,软件维护的过程也会大大简化。可维护性测试可以帮助应用程序的设计更具有容错性,这反过来又意味着软件维护对错误修复的需求将大大降低;这只是说明可维护性测试必要性的一个例子,本指南中还有更多的例子。
为了让客户满意并保持软件产品的功能,进行可维护性测试是至关重要的。
软件维护的测量指标和类型
任何软件都可能经历四种不同类型的维护。这些不同形式的维护分别服务于特定的目标。
- 纠正性维护
无论经过多么广泛的测试,软件产品都可能存在缺陷,而这些缺陷会在没有太多警告的情况下显现出来。发现这些错误并进行修复所需的时间可以衡量软件的可维护性。
-
完善性维护
这种类型的维护主要是通过改进来优化软件。进行这些改进所需的工作量可以用来衡量软件产品的可维护性。在软件中引入新功能所花费的时间和精力可以与预定义的基线或其他以前完成的项目进行比较,以获得准确的评估。 -
适应性维护
除了因改进而产生的修改外,软件产品还经常需要因操作系统更新或程序所依赖的其他软件更新而进行更改。适应性维护包括为保持软件产品与不断变化的环境(如不断变化的硬件和操作系统)兼容而进行的调整。为实现更好的兼容性而引入这些变化所需的时间和精力可以作为衡量软件可维护性的另一个指标。 -
预防性维护
这是对软件进行的维护,目的是减少将来可能需要进行的维护。
对软件进行这些更改是为了先发制人地解决未来的问题,并使软件对可能出现的问题有更强的承受力。
如何衡量应用程序的可维护性?
衡量一个应用程序的可维护性有几个属性。应用程序的可变更性和在变更过程中的稳定性是两个可能的衡量标准。此外,还可以根据分析应用程序以查找错误的难易程度来衡量可维护性。
ISO是国际公认的标准,为系统和软件质量要求和评估(SQuaRE)提供了指南。ISO 25010定义了衡量软件质量的以下特征。
- 模块化
考察应用程序的模块化程度。它评估软件是否由不同的模块化组件组成,或者是否有非模块化的、可能相互依赖的组件。
- 重用性
该标准重点关注已有代码是否可以重新利用,以便在应用程序的其他地方提供类似功能。重复使用代码可以降低成本、提高生产率和整体质量。
- 可分析性:
意外软件缺陷被发现和修复的有效程度。该参数还可用于评估实施某项变更或软件升级的效果。
- 可修改性:
评估在不降低或损害最终产品质量的情况下,应用程序的可修改程度。
- 可测试性
可测试性是指在多大程度上可以为应用程序制定测试标准,以及是否可以通过运行上述测试来检验这些标准是否得到满足。
通过了解各种形式的软件维护和相应的属性来衡量应用程序的可维护性,可维护性测试可以准确地认识到成功和轻松地修复或更新软件的潜力。
可维护性是指更新、修改、重用和测试系统的能力。这对大多数系统都很重要,因为大多数系统在其生命周期内都会被多次更新、修改和测试。通常情况下,系统的各个部分甚至整个系统都会被用于新的和不同的场合。
为什么要对系统进行所有的更改?请记住,当我们讨论可靠性时,我们说过软件不会磨损,但会过时。我们需要新的扩展功能。我们还需要补丁和更新,以使系统运行得更好。我们必须适应新发布的环境,互操作系统也将更新,通常需要对我们的系统进行更新。
设计问题。概念问题。符合标准和指南(或不符合标准和指南)。我们有一个很好的方法来发现这些问题。这就是静态测试。从最初的需求到最新的补丁,可能没有更好的方法来确保系统的可维护性。在这种情况下,一个新工具、几个脚本测试或相当细心的测试人员并不能神奇地将猪耳朵变成丝绸钱包。
必须让管理层了解良好的可维护性所需要的投资。这必须被视为一项长期投资,因为大部分的回报都会在未来的道路上出现。而且,这也是最难出售的一种投资,因为它大多是无形的。如果我们很好地建立了一个可维护的系统,我们如何以有形的方式向管理层展示回报呢?
好吧,我们不会有那么多的补丁,但我们无法毫无疑问地证明这是投资的结果。我们的维护程序员会犯更少的错误,导致更少的回归错误,但我们不一定能指出我们没有犯的错误。
如何进行可维护性测试?
在实施可维护性测试时,并没有硬性的规则来定义需要遵循的流程。一个软件应用程序在发布之前和发布之后,预计会经过多次更新,以纠正错误、引入新功能、调整现有功能和改变非功能性软件特征。
因此,这种测试可能因具体情况而异,实施方法也可能不同。然而,一般来说,通过自动化测试工具,如Selenium或Percy进行可视化测试,可以极大地支持和加快可维护性测试。
测试选项可维护性测试可以使用静态或动态测试方法。作为软件开发过程的一部分,静态测试检查设计文档和源代码的组织、结构、复杂性和其他特性。
静态测试的一些示例如下
- 某些控制结构(如决策语句)的嵌套深度
- 循环复杂性
静态分析和审查是可维护性测试的适当方法,它们应该在设计文档可用时就开始,并在构建应用程序的整个过程中持续进行。
静态分析和评审是可维护性测试的合适方法,应该从设计文档开始,贯穿整个应用程序开发过程。可维护性可以在软件开发生命周期的早期进行评估,而不需要等待一个完成的和可运行的系统,因为可维护性已经融入到代码和每个单独代码组件的文档中。
动态软件测试是为了检查代码的动态特性并确定其功能。它提供了应用程序在使用中的行为的有价值的信息。
动态测量的一些示例包括
- 对更新或错误修复的持续时间进行计时。
- 系统在两次更改之间的稳定性。
动态可维护性测试的重点是为特定的应用程序制定文档化的维护流程,例如对软件进行更改或改进。为了确认规定的服务水平可以通过概述的流程来实现,需要使用各种维护情况作为测试用例。
当支持的基础设施非常复杂,并且可能有多个部门或组织参与支持程序时,这种类型的测试尤为重要。
可维护性测试最佳实践
-
在进行可维护性测试时,有必要制定一个可维护性因素清单,如系统的稳定性或代码的复杂性。
-
确保软件符合数据库、界面和开发过程的适当标准。例如,验证软件是否遵循优化算法和代码重用性等良好实践。
-
创建一个可维护性衡量标准来表示特定因素的可维护性成本和优势是很有帮助的。对于所评估的每个组件,都可以分配一种加权分数,以便进行排序,确定哪些方面需要最大的关注。这有助于制定行动计划,优先解决得分最高的因素。
-
确保软件符合前面讨论的五个可维护性属性: 模块化、可重用性、可分析性、可修改性和可测试性。
易分析性
软件产品被诊断出缺陷或故障原因的能力,或者被识别出需要修改的部分的能力。换句话说,需要花费多少精力才能诊断出系统中的缺陷,或确定需要修改的地方?
以下是可分析性差的四个常见原因,排名不分先后。
-
没有模块化
-
缺乏良好的文档。
-
标准和指南不完善,或者根本不存在。没有编程规范。
-
抽象程度过高
解决大多数问题的方法都是一样的。良好、可靠的标准和指南。随时通过静态测试来执行,尤其是在时间紧迫的情况下。没有借口。如果组织明确指出,可分析性差是一类重要的缺陷,是不能容忍的,那么往往就不会出现这个质量子特性的问题。
内部可分析性指标
- 活动记录
衡量系统状态记录的详尽程度。其计算方法是,计算按照规定写入活动日志的项目数,与根据需求应该写入的项目数进行比较。计算公式为X = A / B
其中,A是实际按照规定写入活动日志的项目数量(经审核确认),B是按照规范规定应写入日志的项目数量。该值越接近1,日志记录就越完整。
- 诊断功能的准备程度
衡量诊断功能提供的全面程度。诊断功能分析故障,并向用户提供输出或日志,解释故障原因。该指标是已实现的诊断功能与技术规范中要求的诊断功能数量的比率,使用相同的公式计算:X = A / B
A是已实施的诊断功能数量(审查中发现),B是技术规范中要求的数量。该指标也可用于衡量系统的故障分析能力和因果分析能力。
外部可分析性指标
组织可能希望跟踪的外部可维护性度量。在测试或维护过程中,当软件被维护或修改时,这些指标有助于测量维护者、用户或系统的行为等属性。
- 审计跟踪能力
衡量用户(或维护者)识别导致故障的具体操作的难易程度。ISO 9126-2在解释如何记录这一指标时有些抽象:它说要观察试图解决故障的用户或维护者。这似乎与该指标的计算方法相悖,即使用公式X = A / B
其中,A是运行期间实际记录的数据项数量,B是为充分监控运行期间软件状态而应记录的数据项数量。与本标准中的许多其他指标一样,企业必须自行定义B的确切值。有多少可能发生的不同错误情况应被记录?X的值越接近1,意味着记录的所需数据越多。组织必须将此视为一种权衡;我们希望记录的越多,就需要编写更多的代码来监控执行、评估发生了什么并记录下来。
- 诊断功能支持
衡量诊断功能支持因果分析的能力。换句话说,用户或维护人员能否识别导致故障的特定功能?与上一个指标一样,应用方法仅指观察用户或维护人员试图使用诊断功能解决故障的行为。计算公式为X = A / B
其中,A是使用诊断功能成功分析的故障数量,B是登记的故障总数。越接近1越好。
- 故障分析能力
衡量用户或维护人员识别导致故障的具体操作的能力。要计算该指标,请使用公式X = 1 - A / B
其中,A是仍未找到原因的故障数量,B是登记的故障总数。请注意,这实际上是上一个指标诊断功能支持的反面。这个指标衡量的是我们无法诊断的故障数量,而上一个指标衡量的是我们诊断出的故障数量。越接近1.0越好。
- 故障分析效率
衡量用户或维护人员分析故障原因的效率。这实质上是对解决系统故障所用平均时间的衡量,计算公式为X = Sum(T) / N。
其中,T是每次解决故障所需的时间,N是已解决问题的数量。该指标的标准中有两个有趣的说明。ISO 9126-2指出,只有成功解决的故障才应包括在此测量中;但是,它接着指出,未解决的故障也应进行测量并一并提交。该标准还指出,在计算这一指标时,可以使用人时而非简单的小时数,这样就可以衡量出努力程度而非简单的经过时间。
- 状态监测能力
衡量在系统实际运行过程中导致故障的操作是否容易获得监控数据。该指标的计算公式为X = 1 - A / B
其中,A是用户或维护人员试图获取监控数据但失败的案例数,B是他们在运行过程中试图获取监控数据的案例数。越接近 1 越好,这意味着他们在尝试获取监控数据时越成功。
可变更性(易修改性 Changeability | Modifiability)
软件产品能够实现特定修改的能力。
几乎所有影响可变更性的因素都是设计和实施实践。
基于设计的问题包括耦合和内聚。耦合和内聚是指系统如何被分割成模块。高耦合度和低内聚性对良好的软件设计是有害的。
耦合是指模块在执行过程中相互依赖内部操作的程度。高耦合意味着模块之间存在大量的依赖关系和共享代码。另一种可能是,一个模块依赖于另一个模块做某事的方式。如果改变这种依赖关系,就会破坏第一个模块。当允许高耦合时,对单个模块进行修改变得非常困难;这里的修改通常意味着那里和那里的更多修改。低耦合是可取的;每个模块都有自己的任务,并且基本上是独立完成的。
有许多不同类型的耦合:
- 内容耦合
当一个模块访问另一个模块的本地数据时。
- 共用耦合:两个或多个模块共享全局数据。
- 外部耦合:两个或多个模块共享一个外部接口或设备。
- 控制耦合:一个模块告诉另一个模块做什么。
- 数据结构耦合:多个模块共享一个数据结构,每个模块只使用其中的一部分。
- 数据耦合:数据从一个模块传递到另一个模块--通常通过参数。
- 消息耦合:模块之间互不依赖;模块之间传递消息而不传递数据。
- 无耦合:模块之间完全不通信。
通常需要一些耦合;模块通常必须能够通信。一般来说,消息耦合或数据耦合是最佳选择。
另一方面,内聚描述了模块职责的集中程度。一般来说,模块应该只做一件事,而且要做得很好。内聚性低的指标包括:模块中的许多函数或方法做不同的事情,而这些事情是不相关的,或者它们处理的是完全不同的数据集。
一般来说,低耦合度和高内聚度是相辅相成的,是可变更性良好的标志。高耦合度和低内聚度通常是设计流程不完善的表现,也是可变更性差的标志。
由不恰当的实现方法引起的可变更性问题涉及到我们在编程课上被告知不能做的许多事情。
使用全局变量是最大的问题之一;它导致了高度的耦合,一个模块中变量的改变可能会对其他模块产生一系列的副作用。
将变量值硬编码到模块中应该被视为一个严重的潜在错误。对于开发人员来说,命名常量是一种更好的编写代码的方式;当他们决定改变值时,所有的实例都会被一次性改变。当使用硬编码值(有些人称之为神奇数字)时,总会有一些被改变,而另一些不会。
对硬件进行硬编码设计也是一个问题。为了提高速度,一些开发人员喜欢按照他们所编写的平台的硬件进行编程。这可能意味着使用操作系统、硬件平台或正在使用的设备的实现细节。当然,当时间流逝,硬件、操作系统和/或设备发生变化时,软件就会出现问题。
系统越复杂,可变性就越差。与往常一样,有时我们需要对复杂性进行权衡。
我们前面提到的Jamie参与的项目,即重写一个中端计算机操作系统,就是软件工程做得很好的一个例子!每个开发人员和大多数测试人员都接受了为期数周的全职面向对象开发和设计培训。他们将2500万行的PL/MP(一种优雅的过程语言)代码转换为C++,这不是一个补丁,而是一次彻底的重写。他们花了大量时间制定每个开发人员都必须遵守的标准和指南。他们在静态测试方面进行了大量投资,并对每个人进行了培训。
低耦合和高内聚是当时的流行语。也许 "流行语 "是不正确的;他们真正相信自己正在做的事情。可维护性是规则。
他们的经验法则是将任何方法、函数或代码限制在打印出来的一页纸上。也许20到25行代码。他们使用良好的面向对象规则,包括类、继承和数据隐藏。他们在模块之间使用消息传递来避免任何全局变量。他们让人编写类库,并对其进行测试,从而真正实现了重复使用。
因此,您可能会认为一切都非常顺利。最终的结果是出色的,但一路上也有不少磕磕绊绊。他们有一个操作系统必须提供的特殊功能;他们估计,使用新的处理器,他们必须在7000个CPU周期内完成任务。重写后,他们发现执行该操作需要超过99,000个CPU周期。他们的误差非常大。而且,由于这个动作每分钟可能会发生数千次,他们的设计需要完全重新考虑。事实上,低耦合、高内聚、继承和数据隐藏都有各自的代价。
每个设计决策都需要权衡利弊。对于许多系统来说,好的设计和技术值得我们为之花费每一分钱。但是,当执行速度是最重要的时候,这些技术往往不能很好地发挥作用。为了使系统正常运行,他们不得不抛弃所有的规则。在这个模块中,他们重新使用了庞大的函数、直接的过程代码、全局变量、低内聚性和高耦合性。而且,他们做得足够快。然而,正如您所期望的那样,它非常容易出问题;花了相当长的时间才稳定下来。
糟糕的文档会对可变更性产生不利影响。如果维护程序员必须猜测如何进行修改,推断原始程序员的想法,那么可变更性就会受到很大影响。文档包括内部文档(代码中的注释,通过良好的命名方式实现代码的自文档化等)和外部文档,包括高层和低层的设计文档。
内部可变更性度量
- 变更可记录性
对规范和程序模块的变更如何完整记录的度量。ISO 9126-3将其定义为代码或其他文档中的变更注释。该指标的计算公式为X = A / B
其中,A是有注释的变更数量(经评审确认),B是变更总数。该值应为0 <= X <= 1,越接近1越好。接近 0 的值表示变更控制不佳。
- 外部可变更性指标
外部可变更性度量有助于衡量当您试图对系统实施变更时所需要的努力。
- 变更周期效率
衡量在可接受的时间内解决用户问题的可能性。该指标通过监控用户与维护者之间的交互,并记录从最初的用户请求到问题解决之间的时间来衡量。该指标的计算公式为Tav = Sum(Tu) / N
其中,Tav为平均时间,Tu为用户从发送问题报告到收到修订版之间的时间,N为发送的修订版数量。Tav越短越好;但是,大量的修订可能会对组织产生反作用,因此应取得平衡。
- 变更执行时间
用于衡量维护人员为解决故障而更改软件的难易程度。计算公式为Tav = Sum(Tm) / N
其中,Tav是平均时间,Tm是检测到故障到找到故障原因之间的时间,N是登记和删除的故障数量。如前所述,有两点需要注意。应排除尚未发现的故障,并且可以使用努力(人-小时)来代替经过时间。时间越短越好。
- 修改复杂性
衡量维护者为解决问题而修改软件的难易程度。计算公式为T = Sum(A / B) / N
其中,T是修复故障的平均时间,A是更改特定故障所花费的工作时间,B是更改的大小,N是更改的次数。变更的大小可以是变更的代码行数、变更的需求数、变更的文档页数等。这个时间越短越好。显然,如果变更的次数过多,企业就应该关注。
- 软件变更控制能力
衡量用户识别软件修订版本的难易程度。这也被列为维护者如何轻松地更改系统以解决问题。其测量公式为X = A / B
其中,A是实际写入变更日志的条目数,B是计划的变更日志条目数,这样我们就可以跟踪软件的变更。越接近1越好,但如果变更很少,该值将趋向于0。
稳定性(Stability,并入Modifiability)
注意ISO25010没有此项。稳定性多和可靠性同义。
系统避免软件修改带来意外影响的能力。当我们对系统进行修改后,会产生多少缺陷?
这个子特性本质上是我们在可变更性中处理的所有问题的副作用。内聚度越低,耦合度越高,编程风格和文档越差,系统的稳定性就越低。
此外,我们还需要考虑需求的质量。如果需求定义明确、理解透彻、管理得当,那么系统往往会更加稳定。如果需求不断变化,并且没有被很好地记录和理解,那么系统的稳定性就会大打折扣。
系统时序对稳定性很重要。在实时系统中,或者当定时非常重要时,变化往往会使定时链发生偏移,从而在其它地方造成故障。
内部稳定性指标
稳定性指标帮助我们预测系统在修改后的稳定性。
- 变更影响
系统修改后不良反应发生频率的度量。该指标的计算公式为:将系统修改后发生的不利影响次数与实际修改次数进行比较X = 1 - A / B
其中,A为不利影响的数量,B为所做修改的数量。越接近1越好。请注意,由于马虎的变更管理方式可能会带来多种不利影响,因此该指标实际上可能为负值。例如,假设进行了一次变更,但出现了三次不良反应。使用该公式计算如下:X = 1 - 3/1 ==> -2.
- 修改影响定位
衡量修改对系统的影响程度。该值通过计算受修改影响的变量数量,并将其与产品中的变量总数进行比较,计算公式为X = A / B
其中,A为审查确认的受影响变量数量,B为变量总数。受影响变量的定义是代码行或计算机指令中被更改的任何变量。该值越接近零,说明修改的影响可能越小。
外部稳定性指标
- 修改成功率: 衡量用户在维护后操作软件系统而不会再出现故障的程度。有两个公式可用于衡量该指标:
-
X = Na / Ta
-
Y = {(Na / Ta) / (Nb / Tb)}
Na是软件更改后用户遇到故障的次数,Nb是软件更改前用户遇到故障的次数,Ta是软件更改后的运行时间(规定的观察时间),Tb是软件更改前的时间(规定的观察时间)。越小越好,越接近0越好。从本质上讲,X 和 Y 代表软件更改后遇到故障的频率。指定的观察时间用于使指标正常化,这样我们就可以更好地比较不同版本的指标。此外,ISO 9126-2还建议,组织可能希望区分同一模块/功能修复后出现的故障和其他模块/功能出现的故障。
- 修改对本地化的影响
这也是衡量用户在维护后能够在不发生进一步故障的情况下操作系统的程度。计算公式为X = A / N
其中,A 是系统修改后(在特定时期内)出现的故障数,N 是解决的故障数。该标准建议跟踪故障的 连锁情况;也就是说,组织应区分因先前故障而归因于变更的故障和似乎与变更无关的故障。越小越好,越接近零越好。
可测试性
可测试性是指软件产品在发生变更后的验证能力。这当然应该是所有技术测试分析师关注的问题。
许多问题都会对系统的可测试性提出挑战。
我们最喜欢的问题之一就是文档。代码中缺乏注释和糟糕的命名习惯,这使得理解代码到底应该做什么变得更加困难。
实施独立的测试团队可能会导致无意的(甚至有时是有意的)沟通中断。在处理可测试性问题时,测试团队和开发团队之间的良好沟通非常重要。
某些编程风格会使代码更难测试。例如,面向对象设计的主要目标之一就是数据隐藏。当然,数据隐藏也会使测试是否通过变得非常困难。多层次的继承使其变得更加困难;您可能不知道事情发生的确切位置,也不知道哪个类(对象)真正负责要采取的行动。
代码中缺乏工具导致可测试性问题。许多系统都具有自我诊断的能力;编写了额外的代码来确保任务正确完成,并记录发生的问题。不幸的是,这些工具通常被视为花哨的东西,而不是必需的。
最后一点,数据问题本身也会导致可测试性问题。在这种情况下,更好的安全性和良好的加密可能会降低系统的可测试性。如果无法找到、测量或理解数据,系统就更难测试。与软件中的许多情况一样,必须做出明智的权衡。
内部可测试性度量
内部可测试性指标衡量测试修改后系统所需的预期工作量。
- 内置测试功能的完整性
衡量内置测试功能的完整性。计算方法是:计算已实现的内置测试功能的数量,并与规范要求的数量进行比较。计算公式为X = A / B
其中,A是已实施的内置测试功能的数量(经审核确认),B是技术规范要求的数量。越接近1,越完整。
- 可测试性的自主性
衡量软件系统可独立测试的程度。该指标的计算方法是:计算使用存根或驱动程序模拟的其他系统的依赖项数量,并将其与其他系统的依赖项总数进行比较。与许多其他指标一样,计算公式为X = A / B
其中,A是使用存根或驱动程序模拟的依赖关系数,B是其他系统的依赖关系总数。越接近1越好。数值为1意味着可以模拟所有其他依赖系统,因此软件(基本上)可以自行测试。
- 测试进度可观察性
测试过程中内置测试结果的完整显示程度。计算公式为X = A / B
其中,A是审查中确认的已执行检查点的数量,B是规范中要求的数量。越接近1越好。
外部可测试性度量
可测试性度量衡量测试修改系统所需的工作量。
- 内置测试功能的可用性
衡量用户或维护者在没有额外的测试设施准备的情况下对系统进行操作测试的难易程度。该指标的计算公式为X = A / B
其中A是维护者可以使用内置测试功能的案例数,B是测试机会数。越接近1越好。
- 重新测试效率
衡量用户或维护者执行操作测试并确定软件是否准备好发布的难易程度。该指标是一个平均值,计算公式为
X = Sum(T) / N
其中,T是在故障解决后确保系统已做好发布准备所花费的时间,N是已解决故障的数量。从本质上讲,这是故障解决后的平均重新测试时间。请注意,未解决的故障不包括在此测量中。越小越好。
- 测试重启性
衡量用户或维护人员在维护后使用检查点执行操作测试的难易程度。计算公式为X = A / B
其中,A是维护者可以在所需位置暂停并重新启动正在执行的测试用例的测试用例数,B是正在执行的测试用例被暂停的测试用例数。越接近 1 越好。
符合性
内部符合性指标
可维护性合规性是对系统在多大程度上符合适用法规、标准和惯例的一种度量。已实施的合规项目(基于审查)与规范中要求合规的项目之间的比率使用以下公式计算X = A / B
其中,A是与可维护性合规性相关的正确执行项目,B是要求的数量。越接近 1,系统的符合性越高。
外部符合性指标
可维护性合规性度量可衡量系统在多大程度上遵守了各种标准、惯例和规定。合规性的测量公式为X = 1 - A / B
其中,A是测试期间未实施的可维护性符合性项目的数量,B是已定义的可维护性符合性项目的总数。越接近 1 越好。
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:【文末小卡片领取】
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!