如果将整个测试体系看成一个国家的话,那么测试分析与设计的过程就是立法的过程,而最终产出的测试方案/点/用例就是一国之法律,每一个测试公民都应该在测试过程中按照这些法律来开展工作。既然是立法,那么就应该从立法动议开始考虑
一、分析测试需求
正如在立法的时候要向各人大机构收集立法建议一样,前期需要对于测试设计进行需求的收集和分析。测试需求的主要来自于开发设计类需求、用户应用类需求和测试经验类需求三方面。
开发设计类需求。
主要包括产品包需求、设计需求、设计规格、产品的软硬件架构等等。事实上,开发设计类需求仅仅是客户需求在开发层面上的一个映像,并非客户需求的本像,因此在收集到这些需求的同时,不仅要关心开发设计类需求文档本身,更应该关注其隐藏的客户实际需求,将其分析透彻,保证测试设计是贴近客户而不是贴近开发,体现端到端的测试设计理念。
比如用户需要做一个烟囱,但开发人员把图纸拿反了,设计成了挖口井。如果测试设计贴近开发的话,那是绝对发现不了这个巨大的错误;如果直接看到的是用户的需求,就能很容易就能找到这其中的阴差阳错。当然,这仅是一个例子,但是在现实中,开发出来的特性不能满足用户需求而被迫返工的事实是存在的,所以在建立测试之法的时候,我们必须要求收集到的动议是最原始需求的反映。
用户应用类需求
这主要包括一些重要的用户实际组网等等,这些都是直接来源于用户的内容,所以可以直接纳入到我们的测试设计中来。
经验类需求
在测试立法的过程中需要将以往的经验固化到文档上形成固定的典型组网、典型应用、典型场景等等。
值得注意的是,经验并不是因循守旧,而应该根据当前技术的发展推陈出新,不断更新再不断固化。比如,早期大家对于STP的理解还停留在STP/RSTP,当时的组网不能满足后续MSTP测试的需求,这就需要在原有组网的基础上设计出新的组网,形成新的经验。
对这三类测试需求分析清楚了,产品“需要测试什么”基本就非常清晰了。接下来,则要根据需求分析分门别类地进行详细设计,也就是要解决“如何测试”的问题,启动真正的设计立法工作。
二、设计测试方案/测试点/测试用例
经过前期的测试需求收集和分析,我们会根据测试对象和范围的不同,把测试设计工作分成三类:特性测试设计、组合测试设计、应用测试设计。特性测试设计主要是针对单个特性进行的设计;组合测试设计主要是将多个相关特性组合起来进行的设计;应用测试设计是根据用户应用而来的专项设计。需要指出的是,实际上组合测试设计和应用测试设计很类似,后者是针对特定用户环境的组合测试设计,也就是说应用测试设计是更加贴近用户实际应用的组合测试设计,无需根据自己的经验再去优化组网,最好按照某用户环境进行1:1的设计。
无论测试设计工作是哪一类,最终体现到实际操作中的内容就是测试方案、测试点、测试用例,即测试的规则。
测试方案
测试方案是对测试活动的总体分析和规划,除了要进行测试对象分析以外,每一个测试方案中都应该包括网络拓扑、网络配置、流量模型。
特性测试方案是最基础的一类,主要用于描述某个单一特性的测试方法和过程。由于特性测试方案主要用于产品功能尚未稳定的测试活动,覆盖产品开发早期阶段,那么势必、存在实际产品物料缺乏的问题,所以在设计特性测试方案时,一定要采用尽可能简单的网络拓扑,避免设计过于复杂;相应的,产品开发早期版本仍然处于功能验证阶段,所以特性测试方案的网络配置应该以被测特性为核心进行配置,避免过多过复杂组合;而流量模型应该采用轻载连续流量比较合适。
组合/应用测试方案一般用于产品相对稳定的阶段,根据组合/应用的需要,可以按需设计网络拓扑和网络配置。有一点需要指出的是,在组合测试方案中一般都愿意采用重载持续流量模型,而在应用类测试方案设计时,需要验证用户组网,所以流量模型也需要考虑符合用户的实际情况,因为重载持续流量模型并不是在所有的用户组网中都能奏效的,有时候在某些特定的用户分布式网络中,轻载叠加突发流量模型也会出现问题。
测试点/用例
测试方案只是对于需要测试的对象进行了整体的分析和分解,接下来则 需要对分析和分解出来的内容进行归纳和整理,这样就形成了测试点。测试点就是测试设计的纲,它是整个设计的灵魂所在。好的测试点应该是测试对象的归纳,测试点安排的顺序是对测试对象剖析的过程,测试点粒度(即测试点包含内容的多少)的选择是对能力基线的严格把握。
由于测试设计人员的思想是千差万别的,所以为了能够得到更加一致的测试点设计,我们采用了测试类型分析法明确了测试点文件的结构,每一个测试点文件中主要包括:配置测试、功能测试、协议一致性测试、性能规格测试、压力测试、异常测试、互操作测试等。而测试点的粒度确实很难统一,所以我们一般按照10个/人天的测试执行效率进行估计和设计,这就需要有丰富测试执行经验。
但是,一个测试点无法详细描述出具体操作的步骤,这便需要测试用例。测试用例设计就是一个将测试点细化到可执行步骤地过程,每一个测试用例都是由执行——〉验证的不停往复。在用例的设计中我们有一些常用的工程方法:边界值法、等价类划分、错误猜测等等。这些无非是扩展我们设计的思路,让测试设计的肉体更加丰满。
三、培养设计人员
在测试全流程中,真正执行者都是有血有肉的个体,而这些人所拥有的经验就是流程的活力。所以要充分发挥测试设计流程的活力,就应该让拥有丰富经验、技术级别高的人来主导测试设计的工作。
在H3C的测试体系中,主要有助理测试工程师、测试工程师、测试专家、资深测试专家等。对于一般的测试设计工作,具有良好测试实践的人员(测试工程师)基本可以胜任;而复杂的跨领域的组网测试设计,除了需要测试实践以外,还需要掌握广泛的数据通信技术知识,这就要求测试专家承担该工作;而资深测试专家则要承担各类更加复杂的疑难杂症的测试设计工作(如黑客攻击测试设计)。
为了适应不同层次的测试设计活动,需要相应的培养不同技术等级的测试人员梯队,尽量物尽其用,高技术等级的从事复杂的设计活动,低技术等级的从事简单的设计活动,不具备设计资质的人员则不能参加设计活动。
四、测试设计维护
实践是检验真理的唯一标准,测试执行是检验测试设计正确性的最佳手段。测试人员需要将将实践中发现的设计问题,通过跟踪流程反馈到设计团队中,使得前期设计的缺陷漏洞得以修复和完备,这样就会形成一个良性的循环。H3C问题单跟踪流程就提供了一个很好的修复机制,不仅从端到端保证设计修改的正确性,而且中间设置的审核环节保证了修改的质量。
五、结束语
测试设计是一个充满创造力的活动,无论是前期的需求分析,还是分析的落实,或是后期对于设计的不断完善。要建立起自己的测试之法,就必须将所有测试设计的活动贯穿到整个测试活动中去,测试执行中体现测试设计的精髓,测试设计吸收测试执行的智慧结晶。
以前做的一个有关Page Cache方面的
测试,今天提出来说说我的测试方法,希望对读者有所帮助。
问题回顾
由于网站被频繁请求的页面为动态生成WEB页,导致消耗大量系统资源,为了提高用户对此类网页访问的响应时间,采用对其该部分页面使用Cache技术。
对于这种类型的测试其实很简单,只要求测试人员做到以下两点就完全可以应付:
1、对Cache在业务中的实现规则有充分了解(具体说来就是,有哪些页面使用了Cache,Cache的有效时间长度为多少,被测服务器端物理内存为多少,分配了多少空间给了Cache)。
2、理解在测试过程中需要重点关注的相关性能计数器(例如内存)。
测试第一步,验证
验证Cache是否存在,是否满足实现规则。例如访问一个已经加有Cache的动态页面,第一次请求的页面响应时间为10秒,第二次为3秒,90 Percent 的响应时间不大于4秒,那么我们暂时可以认为Cache生效。在随后的测试过程中,使用ramp -up 方法对Cache进行测试,看到response time结果大致为,当第一个线程访问该页面时,RPT在一个很高的起点上,因为这时Web 服务器必须访问数据库, 并生成页面,再将其存储在缓存中,这个过程消耗了大部分RPT,运行到第二线程时RPT成曲线下降到一个很低的点上,这是因为第二线程直接从内存中的 Cache里读到了所需的页,这个点和随后增加的线程几乎在同一水平线上,平稳延续,当场景运行到20分钟左右,正好是到了Cache生命周期结束的时间 点上,重复以上描述RPT曲线轨迹。在这里RPT不是随着用户的上升而上升,给人的感觉象是使用了COOKIE。
测试第二步,并发
通过设置并发点对同一动态页面的访问,测试Cache是否有等待时间过长的现象。因为第一到达目的地的线程会先到内存中存储它访问完数据库并生成完页面 的缓存,这个时候其他线程只有乖乖等待第一线程做完写操作后方可进行读操作,大家知道一个线程在一次操作过程中只允许有写或者是读的权限,两种权限不允许 在一个线程内同时进行,如果程序中的线程同步锁处理的不够好,那么可能会导致意外情况发生。例如在多用户同时访问该页面时,可能会出现所有线程请求失败, 遇到这种情况,测试人员可以先多尝试用串行或者不加并发点进行测试并得出结论。根据经验遇到这种问题大多数为线程同步机制出现问题所导致。在测试过程中要 更多关注WEB SERVER 的内存计数器其中包括(页交换比率\ pages reads\ private byte\ working set )如果缓存命中率底,那么内存页交换和pages reads会很高,如果大用户量访问,内存不能及时释放空间,则 working set和private byte会很高,如果怀疑有memory leak现象,可以把其他相关业务同时加上,把执行场景的时间拉长一些,看对其他业务的影响程度。在这里Cache的命中率是Cache的关键问题,如对 以上计数器不是很理解还请查一下相关帮助文件,在这里就不做过多解释了。
使用Cache的优点
节省生成页面时所消耗的CPU和内存资源。对于大用户量的访问使RPT一样变的很短。
对数据库的压力减少是显而易见.我个人觉得这个是最重要优势。
对于最终用户和服务器之间,用户的请求时间变短了,那么就缩小了服务器的资源浪费。
Maven2 基础教程(3) - pom.xml 文件简介
目标
本文用以说明如何修改maven2的主要配置文件pom.xml在适应我们的项目需要,通过本文您可以了解到
- 如何设定编译参数
- 设定编译环境为UTF-8编码
- 添加依赖项
- 添加TestNG框架支持
pom.xml 简介如下是一个最基础的pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.velcro7.framework</groupId> <artifactId>velcro7-base</artifactId> <packaging>jar</packaging> <version>0.1-PROTOTYPE</version> <name>velcro7-base</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies></project>说明了项目的名称,以及依赖于junit的项目。接下来,我们要调整一下编译参数
修改pom.xml调整编译参数编译参数,主要通过使用设定maven-compile-plugin来实现
我们加入如下配置信息
<build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <encoding>utf-8</encoding> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins></build>如上,可以设定编译使用UTF-8编码,源码为JDK1.5的版本,目标也为JDK1.5的版本。
设定使用UTF-8编码除了编译外,还有资源文件、javadoc等都需要告诉maven使用UTF-8编码,我们可以设定如下两个插件
<plugin> <artifactId>maven-resources-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> </configuration></plugin><plugin> <artifactId>maven-javadoc-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> </configuration></plugin>添加TestNG的测试框架支持由于自动生成的项目为使用JUnit的测试框架,但是我们的项目使用TestNG的测试框架,所以我们需要调整一下项目的依赖关系,并且设定项目使用的TesgNG配置文件。
首先删除对于JUnit的依赖
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope></dependency>然后加入如下内容
<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>5.8</version> <scope>test</scope> <classifier>jdk15</classifier></dependency>由于TestNG需要不同的包支持JDK15和JDK14所以在此我们要特别指定<classifier>属性。
如果设定了<version>属性,maven会自动下载依赖项的对应版本,如果没有设置<version>属性,Maven会自动下载最新版本。由于我们项目的开发周期比较长,所以需要指定版本,防止开发过程中由Maven自动更换我们使用的依赖库。
<scope>属性,设定了依赖项的使用范围。如果设定为test表示近测试时使用,在打包时不会打包该文件。
接下来,我们使用插件maven-surfire-plugin设定testNG的配置文件位置,如下
<plugin> <artifactId>maven-surefire-plugin</artifactId> <configuration> <suiteXmlFiles> <suiteXmlFile>testng.xml</suiteXmlFile> </suiteXmlFiles> </configuration></plugin>如上,表示使用testng.xml作为testNG的配置文件。
结束语如上配置,我们最后的配置文件为
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.velcro7.framework</groupId> <artifactId>velcro7-base</artifactId> <packaging>jar</packaging> <version>0.1-PROTOTYPE</version> <name>velcro7-base</name> <url>http://maven.apache.org</url> <build> <plugins> <plugin> <artifactId>maven-resources-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <artifactId>maven-javadoc-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <encoding>utf-8</encoding> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <configuration> <suiteXmlFiles> <suiteXmlFile>testng.xml</suiteXmlFile> </suiteXmlFiles> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>5.8</version> <scope>test</scope> <classifier>jdk15</classifier> </dependency> </dependencies></project>
一些已经从事测试工作三到五年的朋友正在积极的向QA Manager 角色转型,他们对于将来的发展方向也很一致,普遍观点大都是组建一支出色高效的测试团队。最近我也想了一些团队规范和成为具有出色团队称号的必要条件,自己从事测试工作也接近四年了,有些是我在原先工作中遇见并且总结出来的,写的我认为还谈不上全面以后还会逐渐补全。
条件:
缺陷管理
首先正规测试团队至少会有一个缺陷管理系统,不管是Bugzilla还是Mantis 或是其它系统,因为软件测试过程本身就是围绕着缺陷进行的,这也是测试工作的一个重要组成部分。我个人还是比较青睐于使用开源工具。
测试用例谁来写
我不提倡测试新人去写测试用例,这些工作应该分配给那些经验丰富的测试人员去做。新人写测试用例存在一定量的风险性,例如考虑不周达不到预期覆盖率,延缓测试周期和上线时间。
Bug有owner
对于Bug来说,测试人员开启的Bug应该由本人来关闭。做到Bug也要有属主
测试工作量评估
测试工作量应该由测试人员本人估算,从下到上估算工作量,而不是从上到下分派工作量,如果遇到工期固定可以简化测试用例,测试分轻重
Bug描述
Bug一定要做到描述简洁清晰争取做到PD 一看就懂,减少不必要的交流。对于不容易重现的Bug可以清晰的描述操作步骤和具体操作时间产生什么类型的错误。通过以往工作经验个人认为没有不能重现的Bug。
开发人员对测试人员的测试结果产生疑议。如果测试人员根据自己的测试经验判定是个Bug,可以先组织测试人员内部进行缺陷讨论。判定Bug的严重级别后再进行相应处理。有不同看法是正常的,但是不要轻易妥协。
不要浪费测试人员时间。测试人员接到测试任务拿到需测试产品发现低级错误的数量以及功能的不完整性,有权退回。这是在浪费测试人员时间。
测试人员不要过于依赖测试工具
测试人员对测试工具的完全依赖是一种不好的做法,不要忘了最强大的是你的测试思想,在必要的场合采用工具确实能给测试人员带了意想不到的收获但是这只是一种测试手段不能代表测试的全部,如果需要使用工具,我建议往开源方面靠拢。
让测试人员了解产品背后的商业意义
整个项目中什么功能模块是最重要的,为什么要开发这个新功能,这个功能在整个项目中有何种意义,这可以让测试人员对该功能产生一个内心重要级别。对测试用例和以后的回归都起到很大帮助。
营造测试气氛
开发人员开发完功能后需要自测,然后再交送给测试人员,共同把好质量关。开发可能会说我写出来的东西我自己还要测试那还要你做什么。如果开发的产品连正常流程都无法跑通就交给测试被一次一次的打回,这样不光影响项目进度,还可能会导致该测试人员会你开发出的产品有情绪抵触,质量很难得到保证。
测试技术学习
测试团队可以定期拿出一个课题由部分专人负责研究,然后定期Share研究成果组织团队人员研究讨论,促进工作学习两不误。
测试人员不够
如果碰到时间紧任务重测试周期被缩短的情况。我不建议省略写测试计划,测试用例,测试报告去闷头测试。测试可以分轻重,可以申请安排开发做辅助测试。也不能省略那些书面文字。不是走形式。测试人员要彻底认识到这些东西是非常有价值的,在适当时候可以保护你。
先写测试用例再测试不是死规矩。事实上应该是这种工作流程,但是有些时候当没有测试用例思路时,可以先手工运行一遍功能,想到什么写什么,最后形成完整规范测试用例。做到灵活测试。
测试人员有义务向PM阐述对功能的流程以及易用性方面自己的想法。如果是为了功能的可伸缩性那就不仅仅是测试人员需要参与讨论有可能还有PD OP DB等等。最初目的是为了以后如何更方便的开展自动化。让自动化能覆盖的更多更全面。
为了保证产品质量测试越早进行越好。不仅是功能测试,其中也包含性能。
了解当前产品质量
测试人员每个人都应该了解当前产品质量,知道哪块薄弱,知道自己该干什么,提倡每个人都可以提出建设性意见。
开发人员告诉测试人员你应该如何测试。
这种现象可以从多方面理解:
1、作为测试人员你做的不够好,长时间来你充当一个喊话筒的角色,从你以往提交的Bug来看没有任何深度。想受人尊敬受人重视还是要靠自己踏实争取。
2、测试团队不规范,或者说根本就没有测试团队。让开发领着干活自己又不会写代码心理不好受抱怨多多。
更多时候还是需要自己多努力,知识要靠一点一滴的积累。很难重现的Bug你能重现,能告诉开发哪块功能将来可能产生问题,指出系统瓶颈等等类似很多。这些都是需要经验积累。渐渐的你会发现自己在团队中起到了应有的价值得到同事以及上司的认可。
测试环境维护
测试环境由谁来维护其实我觉得并不重要,这里指的谁可以是运维可以是研发可以是QA,但是最好要保证专人来维护,不要谁都可以插手。再没有打招呼的前提下擅自发布新功能或者修改是不可取的。保证版本的统一性很重要。要做到正式发布功能之前OP可以在测试环境下抓取项目整包进行发布。当然对于极小功能小修改可以例外。
收集需求文档
测试人员为了写出一份还算完整的TestCase东奔西跑到处收集信息。开发文档和产品需求文档出炉后请第一时间送交的QA 手里,保证QA的工作开展。
敏捷 反应快速灵敏。
在敏捷软件开发领域,更注重的以人为核心,迭代,循序渐进的开发方法。相比传统的开发方法,这种方法能更快速的开发,上线,反馈,调整、迭代。以敏捷的姿态去发展产品。
敏捷与传统开发的区别
有个非常有意思的游戏能够帮助大家理解敏捷和传统开发的差异。游戏有两个角色,一个是“老板”,另一个是“员工”,在 2 分钟内,“员工”需要在“老板”的完全指挥下,即“向前一步,向后一步,停,向左一步,向右一步”,完成 60步移动的任务。“员工”需要执行“老板”的每一个指令,不允许做出相违背的动作。“老板”则不参与行动,只发出指令指挥“员工”的活动。我们体验这个 游戏 时,当场 60% 的参与者成功完成了任务,大致估计出我们的工作效率是50%*60%=30%。游戏后,参与者被问及对这种行为方式的感受时,无论是“员工”还是“老板”都表示非常不满。
接着,大家又做了另一组游戏。2 分钟内参与者被要求独立的、自主的完成 60 步移动任务,在这次游戏里,所有参与者任务相同,大家可以自行决定、并依据自己的判断随时调整其步伐方向,快慢。最后,我们发现所有参与者不但毫无折扣的 按时完成了任务,因而工作效率也达到 100%*100%=100%,而且所有人对于这种新的工作方式更是产生了极大的兴趣。
敏捷开发与传统开发的比较
通过上面有趣的两种游游戏的对比,以及价值表述的对比就折射出了传统开发与敏捷开发的方式的对比,其中的优劣不言而喻。
敏捷开发
敏捷宣言:
敏捷方法分类:
除了图例中的方法外还有 Crystal, Lean Software Development, Feature Driven Development, Xbreed, RUP 等等。
敏捷方法的共性: 虽然各种敏捷方法的名称、所需环境、适合的团队有很大差异,但是他们拥有相似、相同的以下几大特点:
* 拥抱变化
“唯一不变的就是变化”所以,需求的变动是必不可少的,每次的决定和需求的调整都是将产品开发推向更正确的方向。而在接受变化的同时,我们应该积极的反馈显示活动中暴露出来的可能的设计缺陷和错误。
* 客户的参与
最终使用者、内部使用者、客户代表、商业伙伴都可以是我们的客户。对于客户的参与更能使我们做出客户真正需要的产品。
* 较少的文档
传统开发的文档在敏捷中仍有大用,只是我们可以将原来的文档进行精简。在敏捷中文档不是最佳的沟通方式,更鼓励通畅的交通和沟通,而沟通的效率远高于文档。
* 最大化的生产力
敏捷开发模式要最大化的提高团队的工作效率。无论是依靠剪除冗余的文档工作,还是提供民主的、通畅的沟通平台都是为了帮助 团队能够集中有限的精力处理。
* 测试驱动开发
是让开发人员在编写功能代码之前,根据对需求的理解先设计和编写单元测试代码。先思考如何对将要实现的功能进行验证,再考虑功能的实现。然后迭代的增加新功能的单元测试和功能代码编写,直到完成全部功能的开发。
* 自动化冗余工作
将团队成员从冗余的劳动中解放出来,无论是自动化的测试还是自动化工具的开发只要能够节约成本都是敏捷开发、敏捷测试的目标。
* 民主的团队
敏捷团队是一支民主的团队,团队关系是平行的,每个团队成员能够平等的参与讨论,决策。传统开发的垂直的官僚机构在敏捷开发中已是过时的。
敏捷测试
不是说敏捷测试么?这怎么看上去测试跟敏捷没一毛钱的关系。人家都敏捷了,还要测试做什?
在敏捷开发流程中,测试不再是瀑布试开发流程的一个环节,而是全程参与整个开发流程。通过各种方式来保证产品的质量,无论是原则中的“频繁交 付”,还是对“可工作的软件”的度量,或是敏捷开发实践中的“测试驱动开发”,“行为驱动开发”,都离不开测试的支持。 当然,敏捷测试对测试人员提出了更高的要求,对测试人员来说也是新的挑战。
敏捷测试人员的定义
专业的测试人员,适应变化,与技术人员和业务人员展开良好的协作,并理解利用测试记录需求和驱动开发的思想。
敏捷测试人员往往具有优秀的技术能力,知道如何与他人合作以实现自动化测试,同时也擅长探索性测试,他们希望了解客户在做什么,以此更好地理解客户的软件需求。
敏捷测试思想
对于一个敏捷团队而言,需要持续关注如何最出色地工作并发布最优秀的产品。根据我们的经验,这需要大量的训练、学习、时间、试验和协同工作。
对于一个敏捷测试人员,他(她)会乐于收集和分享信息,与客户或者产品负责人协作以帮助他们充分展示自已的需求,从而得到他们需要的功能,同时向所有人提供项目进展的反馈。
基本要求就是敏捷测试人员和其它敏捷团队成员一样,乐于学习新技能和面对新挑战,不会仅仅局限于测试问题。这不只是测试人员的特征,所有敏捷团 队人员都应具有。敏捷测试人员帮助开发人员和客户团他解决可能出现的任何问题。测试人员提供信息以帮助团队回顾和了解哪些方案有效,哪些无效。
测试人员可能在测试领域拥有特殊的技能和经验,但一名优秀的测试人员并不惧怕参与一场设计讨论,提供有且于测试性或者构建更良好方案的建议。敏捷测试思想是面向结果的、技术性的、协作的,乐于学习的、勇于不断生产业务价值的。
测试人员的十条法则 敏捷测试人员的十条法则:
● 提供持续反馈
● 为客户创造价值
● 进行面对面的沟通
● 勇气
● 简单化
● 持续改进
● 响应变化
● 自我组织
● 关注人
● 享受乐趣
提供持续反馈
既然是测试驱动敏捷项目,那么很显然反馈在敏捷团队中占据重要的地位 。既然是测试驱动敏捷项目,那么很显然反馈在敏捷团队中占据重要的地位 。
为客户创造价值
敏捷开发就是在较低的版本发布中提供客户目前最迫切需要的功能。这通常意味着限定范围。我们经常在客户团队中遇到较酷功能的需求。任何人都可以质疑这些内容,但是测试人员会判断其对故事的影响,因为他们需要考虑测试后果。
进行面对面的沟通
一个团队如果沟通不好则难以协作。如今,许多团队分布于多个地理位置,沟通变得更加重要和富有挑战性。敏捷测试人员应该尽力促进沟通。这是把工作做好的关键因素。
勇气
勇气是极限编程的核心价值,类似测试自动化和持续集成的方式允许团队实践这种价值。 测试人员固守于自己的领域,不与其他业务相关者和技术团队进行任何讨论。虽然你找机会进入了协作的敏捷环境,可能会对找客户索要实例或者找开发人员帮忙自 动化测试或者在每日例会时提出一个难题等感到不习惯。
当最初加入敏捷团队或者当前的团队开始过渡到敏捷开发模式时,通常你会产生恐惧感,并且存在大量的问题需要答案。我们到底如何才能在如此短的时 间内完成对每一个用户故事的测试任务?测试如何跟上开发的节奏?如何确定需要多少测试?又或者你是功能测试经理或者质量过程经理,但不清楚在敏捷团队中如 何定位自己的角色,也没人知道答案。敏捷测试人员需要勇气找到这些问题的答案,但需要勇气的原因不仅限于此。
简单化
敏捷测试人员和他们的团队面临的挑战不仅是生产最简单的有效软件而且还需要采取简单的方法以确保软件符合客户需求。这并不意味着团队不应该花时 间分析主题和故事、思考合适的架构和设计。而是说,当业务部门的需求比较复杂的时候,团队可能需要将方案退回给他们,更简单的解决方案也会产生同样的价 值。
简单并不意味着容易。对于测试人员来说,这意味着采用能够找到的最轻量级的工具和技术恰到好处地测试。工具可以简单到只是一张电子表格或者清单。需要自动化回归测试,但是应该把它们分解到最底层以获取快速反馈。甚至简单的冒烟测试也可能满足面向业务的测试自动化。
持续改进
想办法把工作做得更出色是敏捷测试人员应牢记的。
敏捷测试人员和他们的团队总是在寻找工具、技能或者实践以帮助他们增加更多价值或者得到更好的客户投资回报。敏捷开发的短期迭代更易于尝试新事物,以验证是否值得长期采用。
学习新技能和提高专业技能水平对敏捷测试人员非常重要。可利用各种免费的资源提高专业技能。
响应变化
响应变化是敏捷实践的重要价值,但是我们发现这对测试人员来说却是最困难的概念之一。测试人员渴望的是稳定,所以他们会说:“我已经测试过了, 任务完成了”。持续的需求变化是测试人员的噩梦。但是,作为一名敏捷测试人员,我们不得不拥抱变化。周三,我们可能期望启动故事A和B,下周五做故事C。 但是到了周五,客户重新设定了优先级,现在需要故事A、X和Y。只要我们持续与客户交流,我们就能处理这些变化,因为我们与团队的其他成员保持同步。
自我组织
敏捷测试人员是自组织敏捷团队的组成部分。团队文化贯彻于敏捷测试理念。当开发人员、系统管理员、分析员、数据库专家和客户团队持续关注测试和 测试自动化,测试人员就会获得全新的视角。自动化测试很困难,但是当整个团队都在为此努力时就会简单得多。当大家具有多重技能和多层次视角时,任何测试问 题都会更容易解决。
当敏捷团队面对一个严重问题时,比如进度障碍或者构建失败,该问题将是所有人的问题。最高优先级的问题需要整个团队解决。团队应该立刻讨论并决定解决的办法和相关参与人员。
关注人
只有优秀的员工出色地工作,项目才会成功。敏捷价值和准则的宗旨是确保个人和团队成功。敏捷团队成员应该有安全感。不必担心因犯错受指责或者失 去工作。敏捷团队成员互相尊重并认可个人成就。敏捷团队的所有人应该有机会提高和发展他们的技能。敏捷团队以可持续的步伐前进,使他们能够遵循严格的实践 和保持崭新的视角。正如敏捷宣言所说,我们重视个人和合作超过过程和工具。
享受乐趣
在我们看来,测试人员的理想团队是:所有成员协作,从项目的开始一直到结束,利益相关者与开发团队共同工作,整个团队负责质量和测试。相信很多人都认为每个人都应该在工作中找到乐趣。敏捷开发珍视敏捷测试人员对工作的激情。
敏捷测试人员的工作特别令人满意,因为我们的角度和技能对团队产生了真正的价值。
敏捷测试人员应该做什么?
看了这么多,你一定问:
测试人员在敏捷团队中应该具备什么技能?
测试人员在敏捷团队中从事哪些具体的工作?
在敏捷软件开发过程中开展的测试就可以被称作是敏捷软件测试。因此,敏捷软件测试并不是一个与敏捷软件开发同一层次的划分,而是敏捷软件开发中 的一部分,与传统的测试不同,敏捷软件测试并不是一个独立的过程,相反,它与整个敏捷开发中的其他活动交织在一起,处处都能看到它的影子。由于敏捷软件测 试并不倾向于一个单独的过程定义,本人认为从敏捷软件测试与传统测试观点的比较、敏捷软件测试中采用的方法、测试工程师在敏捷软件测试过程中的工作等方面 来阐述。
回答的很含糊,个人认为敏捷测试人员应该具备的两个主面。
首先,接纳并理解敏捷的核心价值观(沟通,简单,反馈,勇气,尊重、学习、分享)。
其次,测试人员应该具备测试基本技能,当然,可以擅长某个领域,如,探索性测试、单元测试。善于学习与分享,以学习的方式不断的提高自身去适应团队的需求。
我想说的是,不管是从传统开发模式转到敏捷测试,还是重新组建一个敏捷的测试团队。并不是一蹴而就的事儿,需要长期的学习、摸索与改进。当然,前提是以敏捷的价值观为指导思想。
-------------------------------------------------------------
本文引用资料:
段念《什么是敏捷软件测试》
《IBM敏捷测试的最佳实践》
《敏捷软件测试:测试人员与敏捷团队的实践指南》
面对遗留系统,选择合适的测试策略,能让自动化测试的投入在一定时期内看到效果,并且建立可持续进行的机制。同为自动化测试,每种测试在面对遗留系统时遇到的挑战是不同的,起到的效果也不尽相同。
背景
我目前所服务的企业大部分系统是遗留系统,其中多数处于相对需求平稳阶段,即需求并不多,也没有大需求。但这些系统牵制了和需求所需人力不成比例的大量人力,从系统本身的原因看,有这么几点。
● 系统晦涩难懂,可读性可理解性很差。理解原有系统往往占据了进行一个修改的大部分时间。
● 系统设计僵化,改动困难,一个小修改,会迫使系统很多部分的改动。
● 系统难以重用,大多软件单元缺乏可重用性。
● 系统脆弱,引入一个小功能会引入几个缺陷,修复一个缺陷又引起几个新缺陷。
投入大量人力,产生的价值却微乎其微。面对激烈的市场,同质化的竞争,成本和质量问题日益凸显。而所谓遗留系统,即没有自动化测试保护的系统。客户很希望通过引入“自动化测试”来提升系统质量,最终帮助他们建立自动化测试机制。
过去几个月里,我先后投入到几个遗留系统的自动化测试提升工作中。这些工作都进展不错,很多系统的核心模块都有了自动化测试的覆盖。另外,这次专门针对“遗留系统”所做的自动化测试工作,也带给我一些新想法:自动化测试,很可能是我们撬动遗留系统的一个支点。
测试策略选择
图1是测试金字塔模型,从上至下分别是验收测试、API测试、集成测试和单元测试。你可以有不一样的分类,但从上至下,测试粒度越来越小,测试数量越来越多。一个具备完善自动化测试的系统,应该具备类似的测试分布。
图1 测试金字塔模型
当我们面对的是遗留系统时,追求理想模型肯定是不现实的,那么应该选择何种测试策略呢?
每 个遗留系统的状况都不尽相同,可能选择的策略也会不一样。但有一点是一致的——所有的测试都不是没有成本的,在人力并不宽裕的情况下,必须让测试投入“值 回票价”。而且,必须让测试投入到短期最有价值的地方,才能让团队尽快看到效果和建立信心。我们选择的策略之一是:快速建立稳定性较高的功能测试防护墙, 以此保护系统的核心功能不被任意破坏。这里有两个关键点。
● 快速,要选择可以快速建立的测试,让一定的价值在短期之内就能得到体现。
● 稳定,指的是测试本身的稳定——不因系统变化而对测试产生太大的冲击,因而维护成本也就相对较低。
这里的功能测试可以是验收测试、API测试或集成测试,根据每个系统的情况选择更好满足上面两个关键点的测试类型。
例如,我们曾面对一个Web系统,大部分页面逻辑比较简单,主要是呈现内容;前端通过REST接口跟业务后台交互数据。刚开始我们选择基于 WebDriver的验收测试,但随后即发现这类测试编写成本较高,需要学员掌握较多技能,无法在短期内快速为整个系统建立一个防护墙;另一方面,它的稳 定性也较低,测试较易受到页面布局的影响,维护成本较高。在这种情况下,最后我们转而选择了基于REST接口的测试,因为它的建立成本更低,稳定性也更高 (REST接口变化较少),而且也可以覆盖所有核心功能,相比而言,是个更好的选择。
我们还选择了另一个策略:针对热点区域(包括需求热点和缺陷热点等)添加测试。选择这些区域主要基于两点理由。
● 首先,“非热点”区域,也就是暂时稳定的区域,在初期并不是最值得投入为其建立测试的。例如,有个Web系统,它有两个相对独立的组件,一个是社区,另一个是网店,如果前者是热点区域而后者不是,那么前者就更有价值在初期投入建立测试。
● 其次,遗留系统的脆弱性往往体现在“Bug重复出现”、“解决一个Bug,出现两个Bug”等情形。针对这些活跃区域添加测试可以对它们起到保护作用,减少出现上述情况出现的机会;同时,也是对这块区域的一个重构契机。
针对“热点”区域,我们一般会在团队中建立类似“完成新需求必须同时完成测试”、“修复缺陷必须添加测试”这样的纪律。
同时,选择合适粒度的测试也很重要。各类测试自己的优点,例如集成测试在功能保护上体现效果更快;而单元测试却会驱动内部质量的提升。如果条件允许,选择多 种粒度的测试结合,别忘了之前提到的测试金字塔。我们无法为整个系统一下子建立完善的测试,但为某一个区域,是有可能的。
为遗留系统写功能测试
功能测试处于测试金字塔的上端,它的稳定性相对较低,维护成本也较高。因此写功能测试一定要关注提升它的稳定性,并降低维护成本,遗留系统在这几个方面遇到的挑战可能会更大。
最近我对一个Web系统建立基于WebDriver的功能进行测试,其中面临的一个很大问题就是HTML页面缺乏语义、很多元素的定位都得依靠位置等极不可 靠方式,一旦页某些布局发生变化,就会影响到测试,维护成本很高。但事情总有两面性,正是这些测试,让页面的重构和优化得到了团队的重视。
影响功能测试稳定性的另一个重要因素是测试数据。对于团队控制范围内的系统,我的建议是随着测试的建立逐步创建一套可靠的、覆盖各种典型场景的测试数据准备脚本。由此,我们每次都重新建立干净的测试数据,让测试更加稳定和可控。
但在遗留系统中,有时会碰上更严峻的问题,系统依赖于第三方或其他不在控制范围内的测试系统。功能测试会影响到测试数据,因此我们的测试很有可能无法重复执 行。当然,建立一个测试替身系统是一种选择方案,但有时并不容易,至少短期之内。面对这种情况,我们的解决方案是让测试程序和测试数据解耦。想象一下,如 果同样的测试由一个测试人员手工执行,每次执行时不需要选择相同的数据,而只需选择“符合同样要求”的数据。
例如一个电商系统,它出售数量 有限的商品,售完即止。测试数据库中有大量不同商品,但每种商品数量所剩无几。如果我们的商品购买测试程序针对某个特定商品,那么在运行几次之后,商品就 会卖完,测试就不再具备可执行性。但测试人员不会这么傻,他每次都可以选择还有剩余的商品进行购买测试。既然如此,我们的测试程序也同样可以做到:只要根 据商品页面上的信息识别出哪些商品有剩余,随机或者有策略地选择其中某个商品进行购买即可。
这样,我们就让测试程序和具体的测试数据得到了解耦,缓解了测试的不可重复执行性,使其更加稳定,维护成本也得到降低。除了上述方法,还有其他方式可以避免测试程序和测试数据的耦合。
功能测试程序,是在用一种自动化的方式代替人的手工执行,但同时也一定程度上丢失了手工执行的灵活性。让功能测试程序保持灵活应变是我们在编写测试程序时应该考虑的一个重点。
为遗留系统写单元测试
为遗留系统写单元测试会面临和写功能测试不一样的挑战,在复杂度及对人的能力要求上也可能会更高一些。原因并不在于测试,而在于遗留系统自身。遗留系统内部 的强耦合(依赖)及每个单元的高复杂度使得测试难以开展。例如最近我接触的几个遗留系统,线程池逻辑和业务逻辑交织在一起,SQL拼装逻辑、ORM逻辑和 业务逻辑也交织在一起,一个方法往往几百上千行,而且有很深的调用链。
为这样的系统编写单元测试,我们普遍遇到了这样几个问题。
1、私有方法如何测试:我经常被问到的一个问题是“这个私有方法怎么测”?对于私有方法的测试,可能的答案是——不要对私有方法进行测试,只要测试公有方法, 就能覆盖到私有方法。这个答案可能正确,但在遗留系统中,往往是错误的。很多时候,我会反问“为什么要对私有方法进行测试?”
下面这个例子(如图2所示),是一个有较复杂逻辑的线程。但主要的逻辑存在于组装和发起HTTP请求和解析返回的XML上。
图2 一个有较复杂逻辑的线程
当想对私有方法进行测试时,往往意味着类过于复杂、私有方法承载着太多的职责,通过公有方法覆盖私有方法的测试成本过高,难度太大。因此,更好的解决办法是 分离职责、分而治之、单独测试。通过分离职责,单独对各部分逻辑进行测试,测试就会简单很多,如图3所示;另一个例子如图4所示。
图3 单独对各部分逻辑进行测试
图4 另一个案例
如果在不改变代码的前提下为这样的代码写测试,首先要花很多时间理解它,理清各个分支,分别为它们建立复杂的测试准备状态等,成本很高,有时甚至为不可能完成的任务。
2、Mock是否是遗留系统单元测试的“银弹”:当对遗留系统进行单元测试时,Mock作为“银弹”时不时地出现了。面对遗留系统中有较深依赖链的一些方法, 把那些难以建立的依赖统统Mock掉是最快的手段。但经验告诉我:对Mock保持警惕,一旦引入它,就容易被人滥用。当然它本身无错,错在使用它的人,如 果一定要怪Mock,就怪有些Mock工具过于强大吧。滥用Mock会导致:
● 测试真实性的减弱,降低测试程序作为测试本身的价值;
● 滥用Mock的“交互验证(Verification)”,使得测试和实现紧密耦合,降低测试的稳定性。
我专门回顾了之前做的几个系统,发现用到Mock的时候微乎其微,大多使用在对不受控依赖建立测试替身上。在保证测试执行速度的前提下,这是我推荐的做法。但面对遗留系统时,我们很容易把“难以建立依赖测试状态”作为使用Mock的借口,大量滥用。
单元测试,相对于功能测试等高层次的测试,是代码级别的白盒测试。但之于它的测试对象而言,我们仍然应当把单元测试视为黑盒测试——单元级别的黑盒测试。例 如对一个排序方法而言,不管它采用什么排序算法实现,大多情况下我们只在乎它是否可以将一个无序数组排序。它的测试也只要基于输入(无序数组)和输出判断 (有序数组)即可,就算排序算法改变,测试仍然不受影响。从这个排序方法的角度看,测试对它的内部实现不关心,是黑盒的;当内部实现改变时,只要外部行为 不变,测试就不会受到影响。滥用Mock很容易让测试违反这个特质。
此种情况下,我们选择的方案是:选择从依赖链的末端开始测试,从这里开始逐渐完备测试状态准备机制。在保证测试速度(运行速度和编写速度)的前提下,尽量避免使用Mock。当然,如果你的代码依赖复杂、混乱,那么首先可能要重构,重新组织分配职责,简化依赖关系。
简而言之,面对遗留系统进行单元测试时,有几个值得关注的实践:
● 分离职责,分而测之,优于私有方法进行测试;
● 逐步完备测试状态准备机制,优于使用Mock。
之前,我个人对于在遗留系统上实施测试自动化建设是总体悲观的:遗留系统庞大,测试的效果并不会在短期内得以体现;而团队,恰恰经常认为遗留系统足够稳定 (没有什么大需求,而且90%的代码可能短期不需要改动),没有动刀的必要。因此,大多数团队很有可能会在看到测试带来的效果之前就放弃了。
但请相信我,这一切都是假象。故障频发的正是这些遗留系统:
● 稳定是假象,遗留系统里隐藏着很多故障和漏洞,只是暂时没有爆发而已;
● 稳定是假象,粗劣的设计让任何一个需求的变化都会像霰弹一样影响整个系统,遗留系统大都是极其脆弱的。
而单元测试,除了它本身带来的测试价值之外,对于遗留系统而言,更大的部分在于以下三个方面:
● 驱动遗留系统的重构,提升架构设计和内部质量(遗留系统虽庞大,但坏味道其实都雷同)。这是对遗留系统而言最关键但一般情况下最没有可能去做的事情;
● 暴露并解决系统中的缺陷和漏洞,在这个过程中,我们发现并处理了很多漏洞和缺陷,包括多线程处理上、业务逻辑等;
● 更重要的是提升团队的重构和设计能力以及团队质量意识,特别是内部质量。
总结
面对遗留系统,选择合适的测试策略,能够让自动化测试的投入在一定时期内看到效果,并且建立可持续进行的机制。同为自动化测试,每种测试在面对遗留系统时遇 到的挑战是不同样的,它们起到的效果也不尽相同。对于遗留系统而言,功能测试是盾,只有它的保护,我们才能放心地对遗留系统动刀;而单元测试是刃,它撬动 的不仅是遗留系统,更是遗留团队。
摘要:所谓TDD简单地说就是以下两个步骤:确保所有的需求都能被照顾到;在代码不断增加和重构的过程中,可以检查所有的功能是否正确。本文我们一起来看下关于TDD的五大误区。
TDD(全称Test Driven Development)测试驱动开发,是一种软件开发的流程,其由敏捷的“极限编程”引入。其开发过程是从功能需求的测试用例开始,先添加一个测试用例,然后运行所有的测试用例看看有没有问题,再实现测试用例所要测试的功能,然后再运行测试用例,查看是否有case失败,然后重构代码,再重复以上步骤。
其理念主要是确保两件事:
● 确保所有的需求都能被照顾到。
● 在代码不断增加和重构的过程中,可以检查所有的功能是否正确。
原文作者Adam Bar在拜读了Bradley Braithwaite的文章后引发了一些思考,对此,他补充了对TDD的一些看法,列举出TDD的五大误区。以下是文章译文:
1、即使没有单元测试,也比有单元测试做的差要好。 (It's better to have no unit tests than to have unit tests done badly )
2、利用代码测试能够产生许多高效的代码且代码看起来更加可靠、实用。
一、不要使用Mocking Framework VS 太多测试设置
也许有人会说,这两点很矛盾,因为使用Mocking Framework会导致产生过多的测试设置。这就需要我们保持一个良好的平衡问题。
测试代码势必会产生一些依赖关系,倘若不使用Mocking framework,那么我们将无法进行单元测试。这一点是肯定的。
这里例举有关代码测试和数据库的例子——我们通常称之为集成测试、half-arsed测试,这也是测试查询本身唯一可靠的方法。
但是,在大多数情况下,我们使用stubs,避免使用mocks——两者之前的区别非常重要。Mocks作为一种行为测试工具常被用来执行检查过度使用的自定义测试,同一个人在同一时间编写代码,就如同检查我们刚刚故意创建的设计一样。 TDD导致大量的Mock和Stub。Test Case并不一定是那么容易的,如果你的Test Case中的Mock可能是错的,你需要重写他们。也许你会说,就算是不用TDD,在正常的开发过程中,我们的确需要使用Mock和Stub。没错!的确是这样的,不过,记住,我们是在实现代码后来决定什么地方放一个Mock或Stub,而不是在代码实现前干这个事的。所以,TDD中,Test Case是开发中最重要的环节,Test Case的质量的问题会直接导致软件开发的正确和效率。
我们更加关注的是真实的验证结果(stubs将带给你很多帮助),而不是通过耦合来实现。 没有什么比维持一个测试套件和spaghetti-flavoured mock 装置更糟糕的事了。
二、主张太多元素
在每次测试时主张有一个逻辑是很好的规则。即使它意味着调用几个Assert,但对我来说,使用任何asserts 都是同等重要。
三、追溯编写测试
大多数TDD的获益方式,从实施前就可进行思考。比如: 写测试需要成本,测试需要维护。
许多开发者认为这不仅这是通往幸福的路径,还有关于负面的情况及边界值(boundary values )。 此外,它还强烈支持KISS和YAGNI原则,这对于长期代码库来说非常重要。
我个人比较喜欢使用TDD来配合检测错误报告。通过重新创建失败条件来编写失败的单元测试使得更容易,这将有助于隔离故障,分析根本原因所在,这往往比在现实生活的情况下重现 bug容易得多。追溯编写测试只适用于集成测试中查找Bug。
四、测试过多代码
这是一条放之四海而皆准的普遍真理。
在利用单元测试核心代码中我看到许多有价值部分。创建这些代码我更多的是根据TDD原则创建而来(尤其是没有产生错误的代码及没有失败的测试)。
但是我并不把100% 的代码覆盖率作为最终目标,因为这样没有任何意义。
我想,总会有相当多的代码不只是适用于单元测试,即协调/组织类型的代码(我们称之为组成节点将其作为组成root的引用),它们需要一些依赖关系,通过调用几种方法,把代码从这里移植到那里,无需添加任何逻辑,而无需真正干扰数据。
由于其沉重的mocks和stubs 的使用,这种编写测试的代码比代码本身要复杂的多。Bradley的经验法则对我来说:为每一个IF, And,Or,Case,For,While条件语句编写一个单独的测试,当所有分支/条件语句被覆盖时,该代码将会被完全覆盖。
五、TDD跟测试的关系
测试是TDD的必然结果。如果团队一直在实践TDD,所有的代码都会有相应的测试,所有的测试其实就是整个系统的脚手架。 TDD方式的开发是从写测试开始的。
使用TDD时,功能开发总是实现沟通结束条件,也就是在何种情况下,可以认为功能完成,这个结束条件是以测试体现的。
实践TDD时,写代码只有两种目的:1、让一个失败的测试通过。2、在不添加新功能(也就是不需要添加新的测试)的前提下,让代码、结构或者测试更加清晰、整洁、易懂。
对于需求来说,TDD更能引导开发人员做出真正符合需求的东西,不会过渡开发。对于设计来说,TDD的实践能帮你清理思路,但不能教会你做好的设计。对于质量来说,TDD保证所有的代码都有测试覆盖,肯定能提高质量。
写在最后:
对此,有专家建议想要用TDD请首先学会测试的基本功,另外要养成没有测试过的功能坚决不算结束的功能的习惯,这个习惯很重要。为什么TDD狂热者能够report出极少数量的bug的原因之一,就是养成经常性测试的习惯。
使用 TDD 的目的是高效的开发高品质的程序。如果发现 TDD 危及这个目标(没有完美的开发模式,TDD也有自身的弱点和局限),那么请适当的妥协。
摘要:测试用例说明书分成覆盖各个业务流程和预期的输入输出,前者这个有助于与客户沟通,挖掘需求;后者有助于与开发人员的沟通,提高编写符合要求的代码。
正文:测 试用例说明书,通常定义为对一项特定的软件产品进行测试任务的描述,体现测试方案、方法、技术和策略。在软件产品开发中用的非常多,但在项目开发中,重要 性进行经常被忽视,很多项目组都是不做的,或者是为了敷衍编写的。敷衍是有很多原因的,各方不重视测试,需求多变导致测试层本大幅增加、项目时间节点紧, 因此很多测试过程会被简化。很多项目组最后只会有下1-2个左右的测试人员,或者是开发人员做兼职测试,在编码结束后,就上系统点点,然后提交客户了;客 户验收也是同样,验收平台搭建好后,走走流程,可能脑袋里面会想,怎么走流程可以把所有的流程都过一遍么,缺乏系统和专业的考虑。
软件开发,肯定比不上产品开发了,项目的成本、项目结点都是摆在那里的,要说服客户或者领导重视测试不是一朝一夕就能解决的。测试阶段肯定要简化的,但是测试用例说明书还是建议保留的,他的作用不是仅仅停留在测试的。
测试,第一要求的尽可能是测试覆盖业务的所有流程,逻辑分支;第二是测试的依据,不管是覆盖流程、分支还是覆盖页面,都归集为预期输入和预期结果,输入后的结果不是预期的,就是有问题的。
做需求有两个产物:需求规格说明书和页面DEMO,这都是需求静态的描述,你会发现很多客户在项目编码结束测试阶段后会提出很多新增需求和需求变更,有 些程序员会抱怨客户,其实这很大原因就是,静态的需求描述和DEMO很难让客户的思维有所发挥,业务是动态的,做业务的客户的逻辑性和构思不比专业做软件 的,只有等软件动态后才会想到真正的需求,谁都不希望最后一大堆改动,一堆人加班,一大堆风险。测试用例说明书能很好的弥补这个静态的问题,测试用例的业 务流程覆盖测试,动态的描述的业务操作步骤,而且在需求做完确认后就能编写了,因此在需求阶段就做完测试用例说明书,可以有效的改善提高需求设计的质量, 降低后期的需求变更。
上面的作用,是对客户而言,对做需求而言的;而第二个作用是做开发人员而言的。编写好的基本设计交给开发人员开 发,经常会出现最后完成的代码不符合要求,问题可以归咎为开发人员理解有问题或者沟通有问题;也会出现开发人员不负责任,提交的代码问题未经自己测试,测 试的任务推卸给测试人员。问题出在哪里,能不能沟通更加准确,能不能让开发人员更加负责?基本设计有颗粒度到页面级别的,也有到API级别的,但是不管怎 么样,都可以分成预期输入和预期输出,在做完基本设计后,根据基本设计的颗粒度,设计页面或者API预期的输入和预期的输出后,就基本给开发人员定性,编 写完成的代码应该是怎么样的了,这个预期都是测试用例,明确告知开发人员,编写的代码只有达到这个预期后才算完成,可以提交给测试人员测试。通常,开发人 员在明白了预期的输入和输出后,对要编写的代码理解就更加深刻了。
至于测试用例说明书如何写,到底是怎么样的颗粒度,这个我以后在整理,这篇只是说要它的价值所在和重要性。
软件工程中明确写过,测试用例说明书编写在需求阶段和设计阶段,是经过无数项目的总结出来的,只是没体会到而已,这只能说自身功力的问题。
目前团队人数很少,也没有真正意义上的
测试人员,那么如何保证代码质量呢?最近看了《持续交付——发布可靠软件的系统方法》很受启发,突然也想通了很多集成开发工具的设计理念,并做了一些实践,特别记录下来与众人分享。
如何保证代码质量
我觉得根本就是持续集成,确保代码服务器上的版本始终是可运行的。粗粒度上就是把功能分阶段做,每个阶段的功能是完整可发布的,这样有很多好处,尽早看到效果来调整、尽早发现bug、有成果可以鼓舞士气等等;细粒度上就是把每次提交的东西进行测试,让问题尽早暴露尽早修复。
如何达到这个目标呢?原则就是让重复的工作自动化,让测试频繁进行。具体来说就是自动化测试、自动化打包、自动化部署。
自动化测试就是为了能够经常反复的测试才能更早的发现问题。为了让开发人员勤于测试,所以测试的运行时间必须要够短。持续集成推崇的方式是每次提交执行一次测试,这里只做单元测试以确保速度,这也是为什么grails里面把unit单独拿出来鼓励测试。
自动化打包我没用高级的工具,就是利用ant+Ivy写的打包脚本,并借用Grails的思想,通过不同的打包参数可以打出dev、test、prod的包,这样就大大减少人工打包出错的概率。
自动化部署目前我用sae倒是平台就已经支持了,直接上传war包以后,部署都是自动进行的。但是sae的问题就是你本地测试通过的东西,那个环境却不一定行,无比尴尬。
测试种类与分工
测试种类的名词有很多,且最后用的都有很多歧义,特别是集成测试更是有多种含义。我觉得最好理解的划分就是:功能测试(单元测试,组件测试,验收测试)和非功能测试(探索性测试、性能测试、容量测试)。只要能做成自动化的就是开发人员做的;没有办法自动化的就是测试人员做的。
其中,单元测试是不依赖外部只测试某一个类的,为了达到这个效果还有挺多工作的,外部依赖的类要用Mock来模拟,并且尽量不连接数据库这些外部依赖。组件测试就是要有这些外部依赖了,也可以说成是功能测试。验收测试就是模拟用户行为做一系列操作,这个是在最终发布的时候做一次,确保用户使用的正确性。
但注意,每个测试间要做到互相独立,否则会大大增加维护难度。
我期望的效果
单元测试是好东西,但是其实我觉得组件测试是涵盖单元的功能,只是运行时间更长一点而已,但为了减轻测试代码的工作量,我想省去单元测试而全部采用组件 测试。组件测试有一个棘手问题就是用到数据库,而数据库是一个有状态的,测试运行的先后顺序都会影响测试结果,所以最好的办法是让每个测试执行完进行回 滚。
验收测试是个刚学习到的理念,就是把用户对某个功能的一系列操作放在一起进行功能效果验收。虽然会有很大维护量,但是可以有效模拟用户行为,对功能效果进行完整的测试,达到回归测试的效果。
总结一下,就是利用组件测试达到频繁测试的效果,用验收测试达到回归测试效果。
测试框架
为了达到以上效果有什么好的框架,我查了一圈资料,也试了几个框架。Junit4还是被公认最简单有效的框架,并且有众多的扩展插件和IDE支持,但缺 点就是自身功能过于简单。要实现每次测试完的回滚需要结合dbunit,要和spring集成也要自己实现,用到mock也有很多工具可选择。
最后发现一个整合的测试框架Unitlis,它不但整合了以上需求,还简化了配置操作,同时还实现了数据库升级文件的版本管理。试用以后感觉很不错,非常有爱。官方主页是:http://unitils.sourceforge.net/summary.html。
我觉得Unitils有以下几个比较显著的优点:
1、基于反射的断言非常强大,自动过滤掉null和空值,对数组也无视顺序,真的是基于内容本身的比较。
2、集成了spring管理,都是用注解来声明,非常清楚简洁。
3、集成dbunit,配置简化了很多配置,特别对事务回滚配置也很灵活、简单。
4、自带的Mock很好用,语法很漂亮,虽然暂时没打算用。
对于Web测试,我们可以很容易的抓取到相关的http请求包,不用什么专业软件,甚至浏览器都能帮我们完成这个功能,拿到需要的http请求连接 。
http连接对于测试同学来说, 不论做功能、性能或是安全,都是非常重要的, 他过滤了前台的因素,让测试同学直接能对后台进行交互。
以上是http连接的重要性,基本等于废话,下面是正题。
客户端安全测试,同样需要拿到http的请求包,由于客户端的前段限制绕过比较麻烦,那么在做安全测试的过程中,直接拿到http的请求包显得更外重要。
有如下方法可以拿到请求的http包:
1、在不配置代理的情况下,对Android客户端(模拟器)的数据我们可以使用wireshark或者etherpeek等网络层抓包软件抓取,模拟器本身的数据交互是通过电脑主机的网卡进行的,所以我们通过抓包软件抓取主机网卡的数据包,经过过滤,便可得到模拟器客户端中的数据包,类似这样:
访问之后,通过wireshark过滤http请求,便可找到我们刚刚发送的请求。
当然,这是种比较麻烦的方法,不过可以更确切的看到网络包发送的内容。
另一种办法是对模拟器配置代理,让所有请求包可以通过外部主机的七层抓包软件,例如fiddler ,burpsuite等所捕获到,配置代理需要先做一次设置:类似这样:
进 入“设置”选项之后,按照图示设置
这里proxy 设置为10.0.2.2是android模拟器对外部主机地址的硬编码,端口设为8888是外部主机fiddler 的监听地址,当然,如果是burpsuite 可以设置为8080。
那么这样的话 ,我们就能通过fiddler抓取模拟器中的数据包了, 这样对测试来讲,可以用web端的应用层工具对客户端的http数据进行处理,方便的可就多了。