Argument Parsing for Console Applications

  Parsing console application arguments is a basic task for system programmer.

  First, let's clarify some confusing terms:

  Suppose the syntax of a tool is: "tool_name[-a][-b][-c option_parameter] [-d-e][-foption_parameter][operand...]"

  The tool in the example is named as "tool_name". It is followed by options, option-arguments, and operands. The arguments that consist of hyphens and single letters or digits, such as 'a', are known as "options" (or, historically, "flags", "switches"). Certain options are followed by an "option-argument", as shown with [ -c option_argument]. The arguments following the last options and option-arguments are named "operands".

  In general:
  • Argument is parameter that is used to tell applications some specific information in order to accomplish some specific tasks. It can be divided into 3 categories: Option, Option-Parameter and Operand.
  • Option (also named as: flag, switch) is used to customize some default behaviours of program.
  • Option-Parameter is used to provide extra information for the option.
  • Operand is usually source or destination file name, directory name. It will not affect the program's behaviour, but just help program to identify the data to be processed.

  Then, let's see command argument syntax or convention in Winows and *nix world.

POXIS Command Argument Syntax/Convention
  • Arguments are options if they begin with a hyphen delimiter (`-').
  • Multiple options may follow a hyphen delimiter in a single token if the options do not take arguments. Thus, `-abc' is equivalent to `-a -b -c'.
  • Option names are single alphanumeric characters.
  • Certain options require an parameter.
  • An option and its parameter may or may not appear as separate tokens. (In other words, the whitespace separating them is optional.) Thus, `-o foo' and `-ofoo' are equivalent.
  • Options typically precede other non-option arguments.
  • The argument `--' terminates all options; any following arguments are treated as non-option arguments, even if they begin with a hyphen.
  • A token consisting of a single hyphen character is interpreted as an ordinary non-option argument. By convention, it is used to specify input from or output to the standard input and output streams.
  • GNU introduced so called long option style. It starts with '--', the option name consists of letter and '-'. If there is any parameter, it is separated with name by whitespace or '='.
POSIX Option
GNU Long Option
Argument Parsing in TAOUP

Windows Command Argument Syntax/Convention
  • Option consists of an option specifier, either a dash (–) or a forward slash (/), followed by the name of the option.
  • Option names cannot be abbreviated.
  • Some options take an argument, specified after a colon (:) or whitespace.
  • No spaces or tabs are allowed within an option specification, except within a quoted string.
  • Option names and their keyword or filename arguments are not case sensitive, but identifiers as arguments are case sensitive.
  • Use suffix/prefix "+/-" to represent order attribute or addition/removal operation of Options.
  • @fileName.ext style argument specifies that the filename is not used as argument, but the content of the file is used as command argument, plus other normal arguments.
  • To see more concrete examples, run "dir /?", "robocopy /?", "runas /?" and watch the screen output.
MSVS Link.exe Option Syntax
Sqlcmd.exe Option Syntax

Yet Another C++ Command Line Argument Parser - ApCxx
- It supports both Windows convention and Posix/GNU convention
- It supports both ANSI version and Unicode version
- It is implemented in portable C++ code
- It can Get all/specific options/operands
- It can Get all/specific arguments for specific option
- It can check whether some option is give

Source Code download


Option Parsing for C++:

Option Parsing for Other Languages:
C# OptParse
ASM OptParse


Some Tips on Exception Handling

1. Exception V.S. Error Code

- The method you choose depends on how often you expect the event to occur
- Use error code mechanism if it’s a routine case
- Use exception if it’s real exceptional case only
- Never use exception for flow control

2. User Defined Exception

- End user defined exception class names with the word “Exception”
- Ensure that metadata of user defined exceptions is available to code that (may remotely) handles it

3. Exception Safety

- A piece of code is said to be exception-safe, if run time exception will not produce ill effects
- Exception-safe code must satisfy some invariant placed on the code even if exception occurred
- For example, vector<>.add() function should keep the internal state valid/consistent (like element counting) if any exception happened

4. Miscellaneous 

- Always order exceptions in catch blocks from the most specific to the least specific. It handles the specific exception before a general one
- The stack trace begins at the statement where the exception is thrown and ends at the catch statement that catches the exception
- Throw InvalidOperationException if property set or method call is not appropriate given the object state
- Throw ArgumentException if invalid parameters are passed to a function
- Handles resource clean up work in final block
- Logging exception information just once in your whole code stack 


1. .Net Best Practices for Exception Handling
2. .Net Exception Handling Internals
3. Exception Handling Practices for .Net
4. Exception Handling Practices for Java
5. https://en.wikipedia.org/wiki/Exception_safety


CAPTCHA and Modern Attacking Ways

CAPTCHA stands for "Completely Automated Public Turing test to tell Computers and Humans Apart", which is a widely used technology in popular(high traffic) online web services(for example, webmail, ebusiness order confirmation etc) to prevent automatic and abusive client access.

But recently, there are many reports that said CAPTCHA systems of those Internet service providers were cracked and abused by spammers to send huge amount of advertisement junks. So what's the problem of today's CAPTCHA systems?

Traditional CAPTCHA cracking uses OCR techniques to automatically recognize those wired char/text in photos. But the most successful cases use alternative ways that may not be so core-tech related. Security experts call them as Social Engineering, in which people are engaged to do those things that are hard for computer algorithms/softwares.

Under the concept of Social Engineering, there are two concrete methods:
1. Leverage unaware users' efforts of 3rd part service
2. Delegate to people with awareness, the "Mechanical Turk" way

The basic idea of the first method is to redirect CAPTCHA challenges to users of another web service, and use the response results to serve the original web site's CAPTCHA system. Detailed process is described in this article in detail.

The article summarized this method as:
Although it is possible to identify the difference between a computer and a human, there may yet be a challenge in verifying that a given human response is from the intended human.

(from McAfee)

Other case studies of this kind of cracking can be found here and here.

The other social engineering cracking method is reported in this article. It says that:
Spammers are using a variety of techniques to accomplish this. Some of their success is due to their use of "mechanical turks", people who either directly or indirectly create accounts traded online.

Mechanical Turks is an interesting concept which uses manpower to drive some mechanic/automatic services behind the scene. Amazon push this concept into Internet as one of their web services - Amazon MTurk.

This concept is enlarged and advocated as CrowdSourcing by Jeff Howe in the June, 2006 Issue of Wired magazine. The advocators described it as a great way to divide and dispatch tasks to large amount of individual workers to achieve great results in end user's perspective - very similar to what we had done in distributed computing domain.

Turn back to our topic. Due to those fatal defects that exist in today's CAPTCHA systems, some people begin to think CAPTCHA may be not so useful and trustworthy. But CAPTCHA researchers continue their efforts in this field and here is a recent report on this. But in this article, I didn't see how they were going to solve the social engineering problems we described above.

Since manpower is invovled in social engineering, the cost(money) is much higher than compuer software. So the state of today's CAPTCHA system is that, cracking is possible in technical perspective, but it may not be feasible in practice due to huge cost.


Notes: "The Art of Software Testing" - 3

The Art of Software Testing

PART III - 怎样设计测试用例


一 基于白盒测试的用例设计原则

  • 1. 测试的主要关注点(目标):代码覆盖率.
  • 2. 语句覆盖(Statement Coverage)指的是代码被测试时,有多少语句被执行到.这种覆盖的语义太弱,很多逻辑分支无法反映.
  • 3. 判定覆盖(Decision Coverage)将会把所有分支语句的真假分支路径计算在覆盖率统计内,涵盖了语句覆盖的概念.
  • 4. 条件覆盖(Condition Coverage)则是要求每个判断语句中的每个条件表达式所有可能的结果都出现了,才算真正覆盖.但是请注意,判定覆盖不能确保分支覆盖,因为它并没有要求判定语句中不同条件表达式结果的组合情况.
  • 5. 判定条件覆盖,同时满足3和4的要求.但是由于逻辑表达式的by pass优化的存在,有些组合路径并没有考虑进去.
  • 6. 多重条件覆盖(multiple-condition coverage),要求将判断语句中每个条件的不同结果的组合都计算入内,作为测试应该覆盖的目标. 但是由于没有将不同判断语句间的结果进行组合,仍然不能覆盖所有的程序路径.

二 基于黑盒测试的用例设计原则

  • 1. 等价类划分:有很多测试用例,他们发现潜在错误的能力是相同的,这时候,他们属于一个等价类.这个等价类中的任何一个成员用例用作测试,作用是完全一样的.
  • 2. 边界值分析:当对输入参数有范围的限制描述时,比较适合按照边界值来设计多个测试用例.
  • 3. 因果图分析,主要用来处理输入参数进行组合的问题.

三 其它设计用例的方法

  • 1. 错误猜测,是一种依靠直觉来进行用例编写的方法.通过估计程序可能在什么地方出错而设计相应的用例,对程序进行测试.

PART VI - 调试:处理测试结果

一 调试的策略

  • 1. 暴力调试法(Brute Force):通常使用了查看内存,打印信息,集成调试工具等方法.优点是比较直观,能获得很多了解内部状态的机会.但是这忽略了思考的过程,产生的数据量过大,不利于确定问题的效率.
  • 2. 归纳调试法(Induction):归纳是一种从特殊到一般的思维方式和过程.从细节到全局,从线索出发,寻找线索之间的联系,作出假设,再验证假设,最后发现并解决问题.
  • 3. 演绎调试法(Reduction):演绎是从普遍的道理到某一个具体的问题的思考方式.先根据最后的后果列举所有的可能的假设,再利用数据进行排除,最后验证精炼后的假设,最后修改.
  • 4. 回溯调试法(Backtracking),从发生错误的地方,推断造成错误的地方.
  • 5. 测试调试法(Testing),通过修改发现错误的测试用例来帮组进一步发现定位问题.

二 调试的原则

  • 1. 先思考,再调试.
  • 2. 遇困难,先休息.
  • 3. 与人交谈,是发现问题的一种好方法.
  • 4. 尽量避免使用测试工具.
  • 5. 尽量避免使用试验法,尝试法.
  • 6. 存在一个缺陷的地方,往往也存在其它的缺陷
  • 7. 应该意识到修正一个错误可能会引入新的错误.做自动回归测试在修正错误时是非常重要的.
  • 8. 正确修改错误的可能性随着程序规模的增加而降低.

PART V - 新兴测试技术

一 极限测试

  极限编程(eXtreme Programming)是敏捷软件开发(Agile)方法学下的一种软件开发过程,产生的初衷是为了适应社会发展到今天,业务和需求的快速变化.测试在极限编程中处于非常重要的地位,称为"极限测试".

1. 极限编程的基本概念

  • 1). 适合于中小规模,需求快速变化的团队.
  • 2). 需求分析与计划,核心概念:用户场景(User Scenario)来描述需求,客户决定特性(Feature)优先级,开发人员决定功能所需时间.
  • 3). 小规模,不断迭代,递增地发布软件和功能.
  • 4). 系统隐喻(System Metaphor).(不是很理解)
  • 5). 简要设计(Simple Design),假定变化总是会发生,简要设计方便适应变化.
  • 6). 持续测试(Continuous Testing),开发之前编写单元测试用例,不断用测试来验证开发的正确性.
  • 7). 重视重构(Refactoring),迭代的过程里不断优化,重构代码.重构后,需要通过单元测试.
  • 8). 结对编程(Pair Programming),两位程序员用一台电脑进行工作.
  • 9). 代码集体拥有, 代码是由整个团队而不是某个程序员拥有的.
  • 10). 持续集成, 实现每日构建(Daily Build),让最终系统始终可得.
  • 11). 每周工作40小时, 避免加班.
  • 12). 客户在场(on-site customer),由客户不断提出反馈意见.
  • 13). 标准编码,团队所有人提交的代码必须尽量一致.

2. 极限编程下的测试

  • 1). 单元测试:在开发之前编写测试用例,好处:有助开发前了解系统规格;方便重构;开发人员更容易获得信息.由于单元测试需要持续进行,因此一个良好的测试框架,运行和报告工具非常重要.
  • 2). 验收测试:由客户根据用户场景来执行的测试.反馈结果也需要排定优先级.

二 Web测试

1. Web测试面临的挑战

  • 客户端浏览器和操作系统平台千差万别
  • 客户到服务器的连接类型比较多
  • 在涉及金融和财务时,事务概念很重要,测试事务是比较困难的任务
  • 客户可能来自不同的国家和地区,语言,时区,货币符号都需要考虑
  • 由于网站的用户粘着度较低,需要良好的用户体验才能留住客户,如果测试用户体验,是个很困难的问题
  • 网站的在不同负载时的性能表现差别很大,需要模拟各种负载
  • 由于网站的公开性,需要考虑可能的攻击(DoS)

2. 测试策略

  • 事先定义好功能性和非功能性规格说明,作为测试的依据
  • 采用分而治之的方式分别测试表现层,逻辑层和数据层

3. 表示层的测试

  • 内容测试:字体,语法,色彩等等
  • 结构测试:链接,图片,文件的可达性
  • 用户环境:浏览器和操作系统的不同组合,Javascript, ActiveX, Java Applet等等的测试

4. 业务层的测试

  • 性能测试:响应时间和吞吐率,测试时需要模拟典型用户的访问操作
  • 数据验证:测试数据收集模块的功能,检查能否正确处理各种输入
  • 事务测试

5. 数据层测试

  • 响应时间,主要是数据规模达到一定程度时的查询性能
  • 数据完整性,看数据是否满足业务规范
  • 容错性,测试数据库端在容错方面的一些表现


Notes: "The Art of Software Testing" - 2

The Art of Software Testing

Part II - 如何进行测试


1. 代码检查(code inspection)

  1) 活动人员组成:协调人(Drive "Preparing -> Recording -> Ensure Fixing" Process),代码拥有者(Code Owner),其它开发组员(Other Dev Team Member).
  2) 活动内容:逐条讲述/解释代码,其他人提做判断、提意见;对照常见错误列表分析程序.
  3) 会议内容集中于查找错误,而不是改正错误.
  4) 适当控制时间,消耗脑力的会议越长时间越短.
  5) 会后协调人要确保错误被修复,总结错误教训,避免组员犯类似错误.
  6) 会议参与者要对事不对人,代码拥有者要以平和心态接受意见,其它参与者以建设性的态度参与讨论.
  7) 代码检查是个团队内部相互学习的良好机会(编程风格,算法选择,编程技巧等).
  8) 代码检查的最大优势在于尽早发现错误,降低修改成本.
2. 代码走查(code walk through)

  1) 与代码检查不同的地方在于,这里使用的是由人去动态模拟程序运行、检查程序代码正确性.
  2) 全体参会人员用预先选好的数据沿着程序逻辑走一遍,在白板上记录状态和变化.
  3) 为了确保会议的顺利进行,应坚持一个原则:软件中存在的错误不应被视为编写程序的人员自身的弱点,而应被看作软件开发本身的困难.

3. 常见错误检查列表(Code Error Check List)
  1) 变量需要在引用前初始化.
  2) 是否确保数组下表不越界.
  3) 指针变量的值和被指对象的生命周期是否一致(dangling reference).
  4) 动态分配内存、对象的生命周期管理是否清晰、恰当.
  5) 是否考虑了内存地址对齐的问题.
  6) 动态类型转化是否安全(将内存对象解释成另外一个对象类型).
  7) 字符处理时,是否考虑了最后结尾的字符的问题.
  8) 实现类中,是否完成了所有的继承需求.
  9) 变量名是否合理而清晰.

  1) 进行运算的两个数据的类型是否是所期望的.
  2) 混合类型的数据进行运算时是否有清晰的说明.
  3) 是否考虑了运算(中间或者最终结果)可能导致的溢出问题.
  4) 运算结果赋值时,目标变量是否拥有足够的容纳量.
  5) 运算的顺序是否明确清晰.
  6) 除法中除数是否考虑除数可能为0的情况.

  1) 进行比较的数据类型是否一致,特别要注意有符号与无符号数的比较.
  2) 注意在引入“非”运算符号的时候语句的语义是否正确.
  3) 用作逻辑判断的结果是否是布尔型的值.
  4) 复杂的逻辑运算是否确保了清晰正确的顺序.
  5) 是否注意了逻辑运算中的side effect和bypass evaluation.
  1) 循环语句中循环的次数是否确保正确.
  2) 是否对输入的数据进行了假设,这个假设是否体现在输入参数检查和处理中.
  3) 跳转语句(Goto, Break, Continue)是否执行了正确而清晰的语义.
  4) for语句的循环体是否包含了所有想要的语句(忘记{}会引发意外错误).

  1) 是否考虑了参数的压栈顺序与调用风格(cdecl, stdcall).
  2) 是否考虑了传递参数时中间临时对象的创建管理的开销.
  3) 传递内存块时,是否考虑了内存对象的生命期管理问题.
  4) 是否确保没有将函数局部变量(或者局部变量的指针、引用)返回给调用者.
  5) 函数所有的返回路径是否都能正确处理资源释放和临时对象生命周期管理问题.
  6) 在调用函数时,是否考虑了处理所有的返回值和异常情况.

  1) 打开创建文件时的模式、权限的设置是否正确.
  2) 新建文件时是否确保所有的父目录会正确创建.
  3) 文件是否及时清空了缓存.
  4) 是否考虑了I/O系统出错的情况.
  5) 是否确保文件会正确的关闭.
  6) 文件结束的判断是否正确.

  1) 多线程的问题是否考虑了thread safety.
  2) 不同模块内的全局变量是否考虑了初始化顺序问题.
  3) 交叉引用其它模块的全局变量时,变量声明和定义处的类型是否一致.
  4) 引用其它模块的变量时,能否保证引用时变量已经初始化.
  5) 是否消除了所有编译警告.
  6) 进程间同步时是否考虑了可能的死锁问题.


1. 软件开发流程与测试的角色
  1) 典型的软件开发过程:需求分析->[外部规范说明]->系统设计->[系统架构说明]->软件系统设计->[模块接口规范说明]->编码开发  
  2) 对代码的测试,依照模块接口规范进行,称之为"模块测试"(单元测试).
  3) 对整个最终系统按照外部规范说明进行的测试,称之为"功能测试".
  4) 系统开发过程中的测试,大致可以分为:验收测试、系统测试、功能测试、模块测试等.

2. 测试的分类

  1) 验收测试(Acceptance Testing):验收测试是由最终用户进行根据双方签署的合同进行的测试,以检测交付的系统是否满足合同说明.

  2) 功能测试(Function Testing):功能测试是一个试图发现系统和外部规范说明不一致的过程.外部规范说明是一份从最终用户的角度对程序行为的描述.

  3) 系统测试(System Testing):是对一个系统的非功能性方面进行测试.系统规范说明不能作为系统测试的基础,往往用户手册和系统目标文档,才是进行系统测试的基础.系统测试主要包括:

  • a) 容量测试(Volume Testing):是系统经受大数据量的考验.注意这里只强调数据的容量,没有强调时间和其它因素.
  • b) 压力测试(Stress Testing):使系统接受高负载,或者高强度的检验.注意,这里的负载和强度都和时间有关,指的是单位时间内到达的数据或者操作的数量.
  • c) 性能测试(Performance Testing):测试系统在某一用户负载和特定环境配置的条件下的响应时间,吞吐率[throughput](带宽[bandwidth], 每秒操作数[IOPS]).
  • d) 易用性测试(Usability Testing):通常是测试用户使用最终系统是否方便,容易.但是这个测试相对会显得比较主观.易用性测试通常包括衡量完成一件事所需的步骤, 用户用到了多少系统提供的功能, 所有文字输出信息是否语法正确且风格一致,系统是否给予了用户恰当的提示信息等等.
  • e) 安全性测试(Security Testing):主要包括用户的秘密信息(银行帐号,密码)是否被安全地传送,用户的私密信息(偏好,个人隐私)是否被暴露和不恰当收集.
  • f) 兼容性测试(Compatibility Testing):与已有的相关组件,程序是否能很好地配合.对上一版本的系统和软件产生的数据文件是否能正确地识别和转换等等.
  • g) 可恢复测试(Recovery Testing):有很多系统(比如数据库,中间件)都有容错,可恢复功能,能从一些程序错误,硬件失效总回复过来急需工作.需要有一些测试来验证这些功能确实能够正确地工作.
  • h) 可靠性测试(Reliability Testing):有些软件系统(比如航天控制)需要很高的可靠性,因此需要对系统进行相应的测试.但是,通常这样的测试比较难,特别是对高可靠性的系统而言.
  • i) 配置测试(Configuration Testing):系统运行的相关软硬件环境会有多种,应该针对不同的环境测试系统的表现.
  • j) 安装测试(Installation Testing):现代软件的安装往往比较复杂,软件提供方需要对各种情况下的软件安装过程进行测试,以保证其准确无误.
  • k) 国际化测试:主要测试软件在不同的语言配置和环境下是否能正确工作,是否能显示当地的语言,是否能符合当地的时区,用语习惯,货币单位等等.

  4) 单元测试

  • a) 特点:规模小,容易定位错误;方便并行开发测试不同的模块;分离了关注单位的大小,使每个人关注的内容有限.
  • b) 单元测试是一个白盒测试,在现代软件开发中,通常是开发人员完成单元测试.
  • c) 由于各模块单元需要相互调用,因此整个系统有两种方式完成测试:增量方式和非增量方式.前者对模块进行拓扑排序,当所有被依赖的模块都准备好之后才进行后续的测试;后者则需要各模块的开发测试者编写相应的mock/stub模块方便本模块的测试.
  • d) 除了可以减少依赖,方便并行测试,增量模式在其它方面都比非增量模式更有利于系统的开发.
  • e) 增量测试可以按照自上而下和自下而上两种方式进行.自上而下的方法最大有点在于早期演示,激发积极性;缺点在于搭建测试环境比较困难.自下而上的方法则刚好相反.
  • f) 由于单元测试通常需要不断进行,因此辅助的自动化工具非常重要,可以有效提高工作效率.

3. 测试的流程

  1) 测试的计划, 测试计划通常应该包括:

  • 测试目标: 明确的目标可以帮助团队更高效地达到目标.
  • 结束准则: 可以更好地帮组我们明确工作的目标,提高管理的效率.
  • 进度安排: 对细分的工作任务要有明确的时间进度计划.
  • 责任划分: 团队成员的任务要有明确的安排,避免出现责任不明而导致的争端.
  • 测试工具: 测试是需要高度自动化,专业化的工作.相应测试工具的准备,使用都需要计划.
  • 硬件配置: 这是完成真正的测试任务所需资源很重要的一部分.
  • 集成方法: 在多模块的大型系统中,采用什么策略进行系统集成和测试.
  • 测试用例: 测试用例构造的依据和方法.

  2) 测试结束的准则

  • 根据代码覆盖率:当测试用例对被测程序的代码覆盖率达到一定标准时就停止.
  • 根据测试用例覆盖率:根据一些系统方法找出来的用例都跑完之后.
  • 更具用例的数目和发现错误的数目:如果找到的错误达到一定的数目,或者用例达到一定的数据.
  • 根据错误发现和修正的变化趋势:如果单位时间里发现的错误数目在不断下降,或者持续处于低水平,那么继续测试的动力不大.


Notes: "The Art of Software Testing" - 1


The Art of Software Testing

Part I - 关于测试的基本理论


1. 测试是为发现错误而执行程序的过程,而不是为了证明没有错误.这背后的原因在于:

  1). 人类的行为总是倾向于有高度的目标性,确立一个正确的目标有着重要的心理学影响.将目标设置为找到错误,那么发现问题的几率将会增加.
  2). 人们在面对完成的可能性较大(更加现实)的任务时,表现出的效率和积极性更加的高.将软件测试定义为发现错误的活动,而不是证明没有错误,会让这个活动的目标更加切实可行.
  3). 当程序作了不应该做的事情时,也是一种错误.测试过程也许要覆盖程序不应该做的事情.

2. 软件的开发,是一个建设性的过程;而软件测试,则是一个破坏性的过程.

3. 我们希望最后的程序达到这个目标:"做了该做的,没做不该做的."但是通过不断去寻找程序中的错误和问题,是达到这个目标的最佳途径.


1. 黑合测试 - 数据驱动的测试或者输入输出驱动的测试.测试的目标与程序的内部机制和结构无关.从软件规范出发,进行正面和反面两方面进行测试.

2. 白盒测试 - 逻辑驱动的测试.通常从程序的内部构造和逻辑出发,构造测试输入,以覆盖尽可能多的语句路径.但是,即使测试覆盖了所有的语句路径,程序中也有可能存在错误,这些错误与输入数据相关.


1. 要发现程序中所有可能的问题,理论上需要穷举所有的数据输入,这在现实中往往不可能.白盒测试中的路径覆盖是一种很好的简化,但是无法发现所有可能的错误,并且列举空间也非常大.

2. 测试在经济学上的考虑是怎样使用最少的时间,最少的资源(人员、软硬件)发现更多的错误和问题.


1. 对每一个测试用例,都需要对输入和输出的定义.这样我们才能明确判断用例是通过还是失败.

2. 开发人员应该尽量避免测试自己开发的代码.因为他们的头脑处于"建设性"思考的状态,不利于发现存在的问题.

3. 测试应该同时包含正向的和反向的.也就是作,应该覆盖"应该做的",也应该包含“不应该做的”.

4. 尽量保留已有的测试,让测试自动化,可重复,以方便地进行回归测试.

5. 错误通常是聚集出现.如果一个模块错了较多的错误,它出现更多错误的可能性将会更高.

6. 错误发现得越早,改正的成本越低.不要等到项目的最后才开始测试.