欢迎访问lu632的博客
会话
| 会话: | |||||||||
| 在一个RDBMS服务器和一个访问它的用户间的通信期间内发生的一切事情都是发生在一个会 | |||||||||
| 话(session)环境中。当一个客户端应用程序建立了一个到RDBMS服务器的连接时,就说他打开 | |||||||||
| 了一个会话。这个会话就成为了这个应用程序的专有通信通道。这个应用程序的用户可以改变 | |||||||||
| 这个会话环境中的某些参数(如默认的语言或日期格式),这些设置只会影响这个会话环境, | |||||||||
| 且进在这个会话期间保持可用。 | |||||||||
| 日期显示格式的改变: | |||||||||
| SQL> select sysdate from dual; | |||||||||
| SYSDATE | |||||||||
| -------- | |||||||||
| 2005/6/1 | |||||||||
| SQL> alter session set nls_date_format = 'dd-mon-yyyy hh24:mi:ss'; | |||||||||
| セッションが変更されました。 | |||||||||
| SQL> select sysdate from dual; | |||||||||
| SYSDATE | |||||||||
| -------------------- | |||||||||
| 2005/6/1 9:18 | |||||||||
| SQL> alter session set nls_date_format = 'dd-mon-yy'; | |||||||||
| セッションが変更されました。 | |||||||||
| SQL> select sysdate from dual; | |||||||||
| SYSDATE | |||||||||
| --------- | |||||||||
| 1-Jun-05 | |||||||||
| 设置SQL*Plus会话参数: | |||||||||
| SET选项: | 说明: | ||||||||
| AUTO[COMMIT] {ON | OFF | IMMEDIATE} | 这个命令为数据库中要进行的数据改变设置 | ||||||||
| 默认的行为。把它设置为OFF(默认值)要求 | |||||||||
| 用户手工提交改变,发出COMMIT语句。 | |||||||||
| [LIN] ESIZE n | 这个选项设置SQL*Plus可以在一行中显示的 | ||||||||
| 最大字符数;范围从1到由系统决定的最大值。 | |||||||||
| NULL <text> | 这个选项设置当包含NULL的数据被返回时 | ||||||||
| 希望显示的文本。 | |||||||||
| [PAGES] IZE n | 为显示一个查询的结果设置每页最大的行数。 | ||||||||
| [WRA] P(WRA) {ON | OFF} | 这个命令句定了输出数据如何被显示:ON使 | ||||||||
| 得一个必当前行设置更长的返回行可以被换 | |||||||||
| 行到下一行,OFF会把它截取到行的尺寸。 | |||||||||
| 以上可用下面语句在SQL*Plus环境中设置: | |||||||||
| SET <OPTION> [<VALUE>] | |||||||||
| 对于所有待决的事务,当情况为自愿终止时,一个隐式提交将被发出,如果这个会话是异常终止 | |||||||||
| 的话,则会回滚。当一个客户端应用程序突然终止,而没有能力终止它打开到RDBMS服务器的 | |||||||||
| 会话时,孤立会话便会出现。如果这个会话是活动的(即RDBMS正在处理一些命令),则它将自动 | |||||||||
| 探测到客户的缺席并终止这个会话。如果这个会话时不活动的,正在等待來自客戶的命令,則這 | |||||||||
| 樣的一個會話会继续对服务器的使用,因此应该被清除,通常这种工作某一时间间隔后被自动 | |||||||||
| 执行,也可由DBA手工解除。 | |||||||||
约束
| 引用完整性约束可选子句: | ||||||||
| SQL99在FOREIGN KEY和REFERENCES约束的创建上采用了一个可选子句,指定了如果一行有 | ||||||||
| 一个引用关系,而被引用的行被从父表中删除或被引用的行为发生了某些改变,在这种情况下, | ||||||||
| 这个行为会发生什么事情。Oracle没有on update子句。 | ||||||||
| [on delete {no action | cascade | set null } ] | ||||||||
| [on update {no action | cascade | set null } ] | ||||||||
| no action | 是默认行为,意味着如果试图删除被其他表引用的行(或更新主键值), | |||||||
| 则会产生一个错误。 | ||||||||
| cascade | 表现为当改变在父行或父表上发生时,同样的改变也将在外键上发生,如果父行被 | |||||||
| 删除了,则所有引用它的子行也将被删除。如果附表的逐渐被更新了,则所有引用 | ||||||||
| 它的子行的外键也将被同样的值更新。 | ||||||||
| set null | 意味着如果父行被删除或它的主键被改变,则所有子表的引用外键值键被设置为null。 | |||||||
| set default | 类似于set null,但子表的列时被设置为它们的默认值,假定列的默认值是存在的。 | |||||||
| 可延迟约束: | ||||||||
| SQL> create table ex( | ||||||||
| 2 id number not null, | ||||||||
| 3 name varchar2(10) not null, | ||||||||
| 4 sex char(1) default 'm',check(sex in('m','f')) deferrable initially deferred | ||||||||
| 5 ); | ||||||||
| 表が作成されました。 | ||||||||
| SQL> insert into ex values(101,'lili','a'); | ||||||||
| 1行が作成されました。 | ||||||||
| SQL> commit; | ||||||||
| commit | ||||||||
| * | ||||||||
| 行1でエラーが発生しました。: | ||||||||
| ORA-02091: トランザクションがロールバックされました。 | ||||||||
| ORA-02290: チェック制約(FAM03.SYS_C001444386)に違反しました | ||||||||
| SQL> update ex | ||||||||
| 2 set sex = 'f' | ||||||||
| 3 where sex = 'a'; | ||||||||
| 0行が更新されました。 | ||||||||
| SQL> select * from ex; | ||||||||
| レコードが選択されませんでした。 | ||||||||
| SQL> insert into ex values(101,'lili','a'); | ||||||||
| 1行が作成されました。 | ||||||||
| SQL> update ex | ||||||||
| 2 set sex = 'f' | ||||||||
| 3 where sex = 'a'; | ||||||||
| 1行が更新されました。 | ||||||||
| SQL> commit; | ||||||||
| コミットが完了しました。 | ||||||||
| SQL> select * from ex; | ||||||||
| ID NAME S | ||||||||
| ---------- ---------- - | ||||||||
| 101 lili f | ||||||||
黑盒测试的测试用例设计方法
黑盒测试的测试用例设计方法
黑盒测试的测试用例设计方法
·等价类划分方法
·边界值分析方法
·错误推测方法
·因果图方法
·判定表驱动分析方法
·正交实验设计方法
·功能图分析方法
等价类划分:
是把所有可能的输入数据,即程序的输入域划分成若干部分(子集),然后从每一个子集中选取少数具有代表性的数据作为测试用例.该方法是一种重要的,常用的黑盒测试用例设计方法.
1) 划分等价类: 等价类是指某个输入域的子集合.在该子集合中,各个输入数据对于揭露程序中的错误都是等效的.并合理地假定:测试某等价类的代表值就等于对这一类其它值的测试.因此,可以把全部输入数据合理划分为若干等价类,在每一个等价类中取一个数据作为测试的输入条件,就可以用少量代表性的测试数据.取得较好的测试结果.等价类划分可有两种不同的情况:有效等价类和无效等价类.
有效等价类:是指对于程序的规格说明来说是合理的,有意义的输入数据构成的集合.利用有效等价类可检验程序是否实现了规格说明中所规定的功能和性能.
无效等价类:与有效等价类的定义恰巧相反.
设计测试用例时,要同时考虑这两种等价类.因为,软件不仅要能接收合理的数据,也要能经受意外的考验.这样的测试才能确保软件具有更高的可靠性.
2)划分等价类的方法:下面给出六条确定等价类的原则.
①在输入条件规定了取值范围或值的个数的情况下,则可以确立一个有效等价类和两个无效等价类.
②在输入条件规定了输入值的集合或者规定了“必须如何”的条件的情况下,可确立一个有效等价类和一个无效等价类.
③在输入条件是一个布尔量的情况下,可确定一个有效等价类和一个无效等价类.
④在规定了输入数据的一组值(假定n个),并且程序要对每一个输入值分别处理的情况下,可确立n个有效等价类和一个无效等价类.
⑤在规定了输入数据必须遵守的规则的情况下,可确立一个有效等价类(符合规则)和若干个无效等价类(从不同角度违反规则).
⑥在确知已划分的等价类中各元素在程序处理中的方式不同的情况下,则应再将该等价类进一步的划分为更小的等价类.
3)设计测试用例:在确立了等价类后,可建立等价类表,列出所有划分出的等价类:
输入条件 有效等价类 无效等价类
... ... ...
... ... ...
然后从划分出的等价类中按以下三个原则设计测试用例:
①为每一个等价类规定一个唯一的编号.
②设计一个新的测试用例,使其尽可能多地覆盖尚未被覆盖地有效等价类,重复这一步.直到所有的有效等价类都被覆盖为止.
③设计一个新的测试用例,使其仅覆盖一个尚未被覆盖的无效等价类,重复这一步.直到所有的无效等价类都被覆盖为止.
边界值分析法
边界值分析方法是对等价类划分方法的补充.
(1)边界值分析方法的考虑:
长期的测试工作经验告诉我们,大量的错误是发生在输入或输出范围的边界上,而不是发生在输入输出范围的内部.因此针对各种边界情况设计测试用例,可以查出更多的错误.
使用边界值分析方法设计测试用例,首先应确定边界情况.通常输入和输出等价类的边界,就是应着重测试的边界情况.应当选取正好等于,刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据.
(2)基于边界值分析方法选择测试用例的原则:
1)如果输入条件规定了值的范围,则应取刚达到这个范围的边界的值,以及刚刚超越这个范围边界的值作为测试输入数据.
2)如果输入条件规定了值的个数,则用最大个数,最小个数,比最小个数少一,比最大个数多一的数作为测试数据.
3)根据规格说明的每个输出条件,使用前面的原则1).
4)根据规格说明的每个输出条件,应用前面的原则2).
5)如果程序的规格说明给出的输入域或输出域是有序集合,则应选取集合的第一个元素和最后一个元素作为测试用例.
6)如果程序中使用了一个内部数据结构,则应当选择这个内部数据结构的边界上的值作为测试用例.
7)分析规格说明,找出其它可能的边界条件.
错误推测法
错误推测法: 基于经验和直觉推测程序中所有可能存在的各种错误, 从而有针对性的设计测试用例的方法.
错误推测方法的基本思想: 列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据他们选择测试用例. 例如, 在单元测试时曾列出的许多在模块中常见的错误. 以前产品测试中曾经发现的错误等, 这些就是经验的总结. 还有, 输入数据和输出数据为0的情况. 输入表格为空格或输入表格只有一行. 这些都是容易发生错误的情况. 可选择这些情况下的例子作为测试用例.
因果图方法
前面介绍的等价类划分方法和边界值分析方法,都是着重考虑输入条件,但未考虑输入条件之间的联系, 相互组合等. 考虑输入条件之间的相互组合,可能会产生一些新的情况. 但要检查输入条件的组合不是一件容易的事情, 即使把所有输入条件划分成等价类,他们之间的组合情况也相当多. 因此必须考虑采用一种适合于描述对于多种条件的组合,相应产生多个动作的形式来考虑设计测试用例. 这就需要利用因果图(逻辑模型).
因果图方法最终生成的就是判定表. 它适合于检查程序输入条件的各种组合情况.
利用因果图生成测试用例的基本步骤:
(1) 分析软件规格说明描述中, 那些是原因(即输入条件或输入条件的等价类),那些是结果(即输出条件), 并给每个原因和结果赋予一个标识符.
(2) 分析软件规格说明描述中的语义.找出原因与结果之间, 原因与原因之间对应的关系. 根据这些关系,画出因果图.
(3) 由于语法或环境限制, 有些原因与原因之间,原因与结果之间的组合情况不不可能出现. 为表明这些特殊情况, 在因果图上用一些记号表明约束或限制条件.
(4) 把因果图转换为判定表.
(5) 把判定表的每一列拿出来作为依据,设计测试用例.
从因果图生成的测试用例(局部,组合关系下的)包括了所有输入数据的取TRUE与取FALSE的情况,构成的测试用例数目达到最少,且测试用例数目随输入数据数目的增加而线性地增加.
前面因果图方法中已经用到了判定表.判定表(Decision Table)是分析和表达多逻辑条件下执行不同操作的情况下的工具.在程序设计发展的初期,判定表就已被当作编写程序的辅助工具了.由于它可以把复杂的逻辑关系和多种条件组合的情况表达得既具体又明确.
判定表通常由四个部分组成.
条件桩(Condition Stub):列出了问题得所有条件.通常认为列出得条件的次序无关紧要.
动作桩(Action Stub):列出了问题规定可能采取的操作.这些操作的排列顺序没有约束.
条件项(Condition Entry):列出针对它左列条件的取值.在所有可能情况下的真假值.
动作项(Action Entry):列出在条件项的各种取值情况下应该采取的动作.
规则:任何一个条件组合的特定取值及其相应要执行的操作.在判定表中贯穿条件项和动作项的一列就是一条规则.显然,判定表中列出多少组条件取值,也就有多少条规则,既条件项和动作项有多少列.
判定表的建立步骤:(根据软件规格说明)
①确定规则的个数.假如有n个条件.每个条件有两个取值(0,1),故有 种规则.
②列出所有的条件桩和动作桩.
③填入条件项.
④填入动作项.等到初始判定表.
⑤简化.合并相似规则(相同动作).
B. Beizer 指出了适合使用判定表设计测试用例的条件:
①规格说明以判定表形式给出,或很容易转换成判定表.
②条件的排列顺序不会也不影响执行哪些操作.
③规则的排列顺序不会也不影响执行哪些操作.
④每当某一规则的条件已经满足,并确定要执行的操作后,不必检验别的规则.
⑤如果某一规则得到满足要执行多个操作,这些操作的执行顺序无关紧要.
数据库设计说明书
| ||
|
软件需求说明书
|
|
错误处理规范
错误处理规范
概念 | 解释 |
错误 |
|
异常 |
|
错误类型 | 范围 | 处理方式 |
操作员错误 | 与人机界面交互时不满足输入规则、输入范围等发生的错误 |
|
运行时错误 | 与外部资源交互时发生的错误,如网络、文件系统、数据库、其它业务应用系统等 |
|
程序员错误 | 与客户模块交互时不满足前置条件后置条件发生的错误,如类库被其他程序员调用时参数超出范围等 |
|
调用类型 | 处理方式 |
同步调用 |
|
异步调用 |
|
展现方式 | 涉及模块 |
界面提示 |
|
记录日志 |
|
if(xxx == null){
throw new someException();
}
你的代码实际上允许该参数为null,因为你对null的情况进行了运行时处理;尽管你在文档里声明该参数不能为null,但如果客户程序员遵守了约定,那么你这段检查代码就是冗余的
译者注:在写一段程序时,如果没有用try-catch捕捉异常或者显式的抛出异常,而希望程序自动抛出,一些语言的编译器不会允许编译通过,如Java就是这样。这就是Checked Exceptions最基本的意思。该特性的目的是保证程序的安全性和健壮性。Zee&Snakey(MVP)对此有一段很形象的话,可以参见http://www.blogcn.com/user2/zee/main.asp。Bruce Eckel 也有相关的一篇文章:《Does Java need Checked Exceptions》,参见http://www.mindview.net/Etc/Discussions/CheckedExceptions
Bruce Eckel | C#没有Checked Exceptions,你是怎么决定是否在C#中放置这种特性的么? |
Anders Hejlsberg | 我发现Checked Exceptions在两个方面有比较大的问题:扩展性和版本控制。我知道你也写了一些关于Checked Exceptions的东西,并且倾向于我们对这个问题的看法。 |
|
|
Bruce Eckel | 我一直认为Checked Exceptions是非常重要的。 |
Anders Hejlsberg | 是的,老实说,它看起来的确相当重要,这个观点并没有错。我也十分赞许Checked Exceptions特性的美妙。但它某些方面的实现会带来一些问题。例如,从Java中Checked Exceptions的实现途径来看,我认为它在解决一系列既有问题的同时,付出了带来一系列新问题的代价。这样一来,我就搞不清楚Checked Exceptions特性是否可以真的让我们的生活变得更美妙一些。对此你或许有不同看法。 |
|
|
Bruce Eckel | C#设计小组对Checked Exceptions特性是否有过大量的争论? |
Anders Hejlsberg | 不,在这个问题上,我们有着广泛的共识。C#目前在Checked Exceptions上是保持缄默的。一旦有公认的更好的解决方案,我们会重新考虑,并在适当的地方采用的。我有一个人生信条,那就是——如果你对该问题不具有发言权,也没办法推进其解决进程,那么最好保持沉默和中立,而不应该摆出一个非此即彼的架势。 假设你让一个新手去编一个日历控件,他们通常会这样想:“哦,我会写出世界上最好的日历控件!我要让它有各种各样的日历外观。它有显示部分,有这个,有那个……”他们将所有这些构想都放到控件中去,然后花两天时间写了一个很蹩脚的日历程序。他们想:“在程序的下一个版本中,我将实现更多更好的功能。” 但是,一旦他们开始考虑如何将脑海中那么多抽象的念头具体实现出来时,就会发现他们原来的设计是完全错误的。现在,他们正蹲在一个角落里痛苦万状呢,他们发现必须将原来的设计全盘抛弃。这种情况我不是看到一次两次了。我是一个最低纲领主义者。对于影响全局的问题,在没有实际解决方案前,千万不要将它带入到整个框架中去,否则你将不知道这个框架在将来会变成什么样子。 |
|
|
Bruce Eckel | 极限编程(The Extreme Programmers)上说:“用最简单的办法来完成工作。” |
Anders Hejlsberg | 对呀,爱因斯坦也说过:“尽可能简单行事。”对于Checked Excpetions特性,我最关心的是它可能给程序员带来哪些问题。试想一下,当程序员调用一些新编写的有自己特定的异常抛出句法的API时,程序将变得多么纷乱和冗长。这时候你会明白Checked Exceptions不是在帮助程序员,反而是在添麻烦。正确的做法是,API的设计者告诉你如何去处理异常而不是让你自己想破脑袋。 |
Bill Venners | 你提到过Checked Exceptions的扩展性和版本相关性这两个问题。现在能具体解释一下它们的意思么? |
Anders Hejlsberg | 让我首先谈谈版本相关性,这个问题更容易理解。假设我创建了一个方法foo,并声明它可能抛出A、B、C三个异常。在新版的foo中,我要增加一些功能,由此可能需要抛出异常D。这将产生了一个极具破坏性的改变,因为原来调用此方法时几乎不可能处理过D异常。 也就是说,在新版本中增加抛出的异常时,给用户的代码带来了破坏。在接口中使用方法时也有类似的问题。一个实现特定功能的接口一经发布,就是不可改变的,新功能只能在新版的接口中增加。换句话说,就是只能创建新的接口。在新版本中,你只有两种选择,要么建立一个新的方法foo2,foo2可以抛出更多的异常,要么在新的foo中捕获异常D,并转化为原来的异常A、B或者C。 |
|
|
Bill Venners | 但即使在没有Checked Exceptions特性的语言中,(增加新的异常)不是同样会对程序造成破坏么?假如新版foo抛出了需要用户处理的新的异常,难道仅仅因为用户不希望这个异常发生,他写代码时就可以置之不理吗? |
Anders Hejlsberg | 不,因为在很多情况下,用户根本就不关心(异常)。他们不会处理任何异常。其实消息循环中存在一个最终的异常处理者,它会显示一个对话框提示你程序运行出错。程序员在任何地方都可以使用try finally来保护自己的代码,即使运行时发生了异常,程序依然可以正确运行。对于异常本身的处理,事实上,程序员是不关心的。 很多语言的throws语法(如Java),没必要地强迫你去处理异常,也就是逼迫你搞清楚每一个异常的来源。它们要求你要么捕获声明的异常,要么将它们放入throws语句。程序员为了达到这个要求,做了很多荒谬可笑的事情。例如他们在声明每个方法时,都必须加上修饰语:“throws Exception”。这完全是在搧这个特性的耳光,它不过是要求程序员多作些官样文章,对谁都没有好处 |
|
|
Bill Venners | 如此说来,你认为不要求程序员明确的处理每个异常的做法,在现实中要适用得多了? |
Anders Hejlsberg | 人们为什么认为(显式的)异常处理非常重要呢?这太可笑了。它根本就不重要。在我印象中,一个写得非常好的程序里,try finally和try catch语句数目大概是10:1。在C#中,也可以使用和类似try finally的using语句(来处理异常) |
|
|
Bill Venners | finally到底干了些什么? |
Anders Hejlsberg | finally保证你不被异常干扰,但它不直接处理异常。异常处理应该放在别的什么地方。实际上,在任何一个事件驱动的(如现代图形界面)程序中,在主消息循环里,都有一个缺省的异常处理过程,程序员只需要处理那些没被缺省处理的异常。但你必须确保任何异常情况下,原来分配的资源都能被销毁。这样一来,你的程序就是可持续运行的。你肯定不希望写程序时,在100个地方都要处理异常并弹出对话框吧。如果那样的话,你作修改时就要倒大霉了。异常应该集中处理,并在异常来临处保护好你的代码 |
Bill Venners | 那么Checked Exceptions的扩展性又是如何呢? |
Anders Hejlsberg | 扩展性有时候和版本性是相关的。 在一个小程序里,Checked Exceptions显得蛮迷人的。你可以捕捉FileNotFoundException异常并显示出来,是不是很有趣?这在调用单个的API时也挺美妙的。但是在开发大系统时,灾难就降临了。你计划包含4、5个子系统,每个子系统抛出4到10个异常。但是(实际开发时),你每在系统集成的梯子上爬一级,必须被处理的新异常都将呈指数增长。最后,可能每个子系统需要抛出40个异常。将两个子系统集成时,你将必须写80个throw语句。最后,可能你都无法控制了。 很多时候,Checked Exceptions都会激怒程序员,于是程序员就想办法绕过这个特性。他要么在到处都是写“throws Exception”,要么——我都不知道自己看到多少回了——写“try, da da da da da(译者注:意思是飞快的写一段代码), catch curly curly(译者注:即‘{ }’)”,然后说:“哦,我会回头来处理这些空的异常处理语句的。”实际上,理所当然的没有任何人会回头干这些事情。这时候,Checked Exceptions已经造成系统质量的极大下降。 所以,你可能很重视这些问题,但是在我们决定是否将Checked Exceptions的一些机制放入C#时,却是颇费了一番思量的。当然,知道什么异常可能在程序中抛出还是有相当价值的,有一些工具也可以作这方面的检查。我不认为我们可以建立一套足够严格而严谨的规则(来完成异常检查),因为(异常)还可能是编译器的错误引起的呢。但是我认为可以在(程序)分析工具上下些功夫,检测是否有可疑代码,是否有未捕获的异常,并将这些隐藏的漏洞给你指出来 |
错误处理规范
错误处理规范
概念 | 解释 |
错误 |
|
异常 |
|
错误类型 | 范围 | 处理方式 |
操作员错误 | 与人机界面交互时不满足输入规则、输入范围等发生的错误 |
|
运行时错误 | 与外部资源交互时发生的错误,如网络、文件系统、数据库、其它业务应用系统等 |
|
程序员错误 | 与客户模块交互时不满足前置条件后置条件发生的错误,如类库被其他程序员调用时参数超出范围等 |
|
调用类型 | 处理方式 |
同步调用 |
|
异步调用 |
|
展现方式 | 涉及模块 |
界面提示 |
|
记录日志 |
|
if(xxx == null){
throw new someException();
}
你的代码实际上允许该参数为null,因为你对null的情况进行了运行时处理;尽管你在文档里声明该参数不能为null,但如果客户程序员遵守了约定,那么你这段检查代码就是冗余的
译者注:在写一段程序时,如果没有用try-catch捕捉异常或者显式的抛出异常,而希望程序自动抛出,一些语言的编译器不会允许编译通过,如Java就是这样。这就是Checked Exceptions最基本的意思。该特性的目的是保证程序的安全性和健壮性。Zee&Snakey(MVP)对此有一段很形象的话,可以参见http://www.blogcn.com/user2/zee/main.asp。Bruce Eckel 也有相关的一篇文章:《Does Java need Checked Exceptions》,参见http://www.mindview.net/Etc/Discussions/CheckedExceptions
Bruce Eckel | C#没有Checked Exceptions,你是怎么决定是否在C#中放置这种特性的么? |
Anders Hejlsberg | 我发现Checked Exceptions在两个方面有比较大的问题:扩展性和版本控制。我知道你也写了一些关于Checked Exceptions的东西,并且倾向于我们对这个问题的看法。 |
|
|
Bruce Eckel | 我一直认为Checked Exceptions是非常重要的。 |
Anders Hejlsberg | 是的,老实说,它看起来的确相当重要,这个观点并没有错。我也十分赞许Checked Exceptions特性的美妙。但它某些方面的实现会带来一些问题。例如,从Java中Checked Exceptions的实现途径来看,我认为它在解决一系列既有问题的同时,付出了带来一系列新问题的代价。这样一来,我就搞不清楚Checked Exceptions特性是否可以真的让我们的生活变得更美妙一些。对此你或许有不同看法。 |
|
|
Bruce Eckel | C#设计小组对Checked Exceptions特性是否有过大量的争论? |
Anders Hejlsberg | 不,在这个问题上,我们有着广泛的共识。C#目前在Checked Exceptions上是保持缄默的。一旦有公认的更好的解决方案,我们会重新考虑,并在适当的地方采用的。我有一个人生信条,那就是——如果你对该问题不具有发言权,也没办法推进其解决进程,那么最好保持沉默和中立,而不应该摆出一个非此即彼的架势。 假设你让一个新手去编一个日历控件,他们通常会这样想:“哦,我会写出世界上最好的日历控件!我要让它有各种各样的日历外观。它有显示部分,有这个,有那个……”他们将所有这些构想都放到控件中去,然后花两天时间写了一个很蹩脚的日历程序。他们想:“在程序的下一个版本中,我将实现更多更好的功能。” 但是,一旦他们开始考虑如何将脑海中那么多抽象的念头具体实现出来时,就会发现他们原来的设计是完全错误的。现在,他们正蹲在一个角落里痛苦万状呢,他们发现必须将原来的设计全盘抛弃。这种情况我不是看到一次两次了。我是一个最低纲领主义者。对于影响全局的问题,在没有实际解决方案前,千万不要将它带入到整个框架中去,否则你将不知道这个框架在将来会变成什么样子。 |
|
|
Bruce Eckel | 极限编程(The Extreme Programmers)上说:“用最简单的办法来完成工作。” |
Anders Hejlsberg | 对呀,爱因斯坦也说过:“尽可能简单行事。”对于Checked Excpetions特性,我最关心的是它可能给程序员带来哪些问题。试想一下,当程序员调用一些新编写的有自己特定的异常抛出句法的API时,程序将变得多么纷乱和冗长。这时候你会明白Checked Exceptions不是在帮助程序员,反而是在添麻烦。正确的做法是,API的设计者告诉你如何去处理异常而不是让你自己想破脑袋。 |
Bill Venners | 你提到过Checked Exceptions的扩展性和版本相关性这两个问题。现在能具体解释一下它们的意思么? |
Anders Hejlsberg | 让我首先谈谈版本相关性,这个问题更容易理解。假设我创建了一个方法foo,并声明它可能抛出A、B、C三个异常。在新版的foo中,我要增加一些功能,由此可能需要抛出异常D。这将产生了一个极具破坏性的改变,因为原来调用此方法时几乎不可能处理过D异常。 也就是说,在新版本中增加抛出的异常时,给用户的代码带来了破坏。在接口中使用方法时也有类似的问题。一个实现特定功能的接口一经发布,就是不可改变的,新功能只能在新版的接口中增加。换句话说,就是只能创建新的接口。在新版本中,你只有两种选择,要么建立一个新的方法foo2,foo2可以抛出更多的异常,要么在新的foo中捕获异常D,并转化为原来的异常A、B或者C。 |
|
|
Bill Venners | 但即使在没有Checked Exceptions特性的语言中,(增加新的异常)不是同样会对程序造成破坏么?假如新版foo抛出了需要用户处理的新的异常,难道仅仅因为用户不希望这个异常发生,他写代码时就可以置之不理吗? |
Anders Hejlsberg | 不,因为在很多情况下,用户根本就不关心(异常)。他们不会处理任何异常。其实消息循环中存在一个最终的异常处理者,它会显示一个对话框提示你程序运行出错。程序员在任何地方都可以使用try finally来保护自己的代码,即使运行时发生了异常,程序依然可以正确运行。对于异常本身的处理,事实上,程序员是不关心的。 很多语言的throws语法(如Java),没必要地强迫你去处理异常,也就是逼迫你搞清楚每一个异常的来源。它们要求你要么捕获声明的异常,要么将它们放入throws语句。程序员为了达到这个要求,做了很多荒谬可笑的事情。例如他们在声明每个方法时,都必须加上修饰语:“throws Exception”。这完全是在搧这个特性的耳光,它不过是要求程序员多作些官样文章,对谁都没有好处 |
|
|
Bill Venners | 如此说来,你认为不要求程序员明确的处理每个异常的做法,在现实中要适用得多了? |
Anders Hejlsberg | 人们为什么认为(显式的)异常处理非常重要呢?这太可笑了。它根本就不重要。在我印象中,一个写得非常好的程序里,try finally和try catch语句数目大概是10:1。在C#中,也可以使用和类似try finally的using语句(来处理异常) |
|
|
Bill Venners | finally到底干了些什么? |
Anders Hejlsberg | finally保证你不被异常干扰,但它不直接处理异常。异常处理应该放在别的什么地方。实际上,在任何一个事件驱动的(如现代图形界面)程序中,在主消息循环里,都有一个缺省的异常处理过程,程序员只需要处理那些没被缺省处理的异常。但你必须确保任何异常情况下,原来分配的资源都能被销毁。这样一来,你的程序就是可持续运行的。你肯定不希望写程序时,在100个地方都要处理异常并弹出对话框吧。如果那样的话,你作修改时就要倒大霉了。异常应该集中处理,并在异常来临处保护好你的代码 |
Bill Venners | 那么Checked Exceptions的扩展性又是如何呢? |
Anders Hejlsberg | 扩展性有时候和版本性是相关的。 在一个小程序里,Checked Exceptions显得蛮迷人的。你可以捕捉FileNotFoundException异常并显示出来,是不是很有趣?这在调用单个的API时也挺美妙的。但是在开发大系统时,灾难就降临了。你计划包含4、5个子系统,每个子系统抛出4到10个异常。但是(实际开发时),你每在系统集成的梯子上爬一级,必须被处理的新异常都将呈指数增长。最后,可能每个子系统需要抛出40个异常。将两个子系统集成时,你将必须写80个throw语句。最后,可能你都无法控制了。 很多时候,Checked Exceptions都会激怒程序员,于是程序员就想办法绕过这个特性。他要么在到处都是写“throws Exception”,要么——我都不知道自己看到多少回了——写“try, da da da da da(译者注:意思是飞快的写一段代码), catch curly curly(译者注:即‘{ }’)”,然后说:“哦,我会回头来处理这些空的异常处理语句的。”实际上,理所当然的没有任何人会回头干这些事情。这时候,Checked Exceptions已经造成系统质量的极大下降。 所以,你可能很重视这些问题,但是在我们决定是否将Checked Exceptions的一些机制放入C#时,却是颇费了一番思量的。当然,知道什么异常可能在程序中抛出还是有相当价值的,有一些工具也可以作这方面的检查。我不认为我们可以建立一套足够严格而严谨的规则(来完成异常检查),因为(异常)还可能是编译器的错误引起的呢。但是我认为可以在(程序)分析工具上下些功夫,检测是否有可疑代码,是否有未捕获的异常,并将这些隐藏的漏洞给你指出来 |
系统测试设计的层次
系统测试设计的层次
随着国内软件行业的不断发展,国内软件公司也越来越注重于软件的质量,越来越关注软件的可靠性,因此,做为质量保证的重要手段,软件测试过程的实施与管理成为一个热点,其中系统测试是整个测试活动的一个重要的阶段,系统测试的设计也就成为了关注点之一。以下是本人从事系统测试工作中的一些体会。
1、系统测试的定义:
系统测试是针对整个产品系统进行的测试,目的是验证系统是否满足了需求规格的定义,找