已阅读5页,还剩12页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
为PL/SQL构建代码分析实用工具(一)作者:Steven Feuerstein 来源:OTN在这共有 8 个部分组成的系列中, Steven Feuerstein PL/SQL 语言方面的世界顶尖专家(自 2001 年始就是 OTN 成员),解释了他如何创建 Codecheck 一个 PL/SQL 实用工具,依靠数据字典中的信息来分析歧义超载包。Steven Feuerstein 是 Oracle PL/SQL 语言方面的世界顶尖的专家。他编著或者合著了九本关于 PL/SQL 的书,包括 Oracle PL/SQL 编程,第三版 ,和 Oracle PL/SQL 最佳应用 ( OReilly & Associates 出版社, / )。他是 Quest Software 的高级技术顾问,从 1980 年就开始开发软件, 1987 至 1992 年间为 Oracle 公司工作。他也是 Crossroads 基金的前董事会主席,这一基金为芝加哥地区争取社会、种族和经济平等的社区组织 ( www.CrossroadsF ) 提供资助。下载 codecheck.zip第 1 部分:构建一个代码分析实用工具,并在第一次就正确执行 在这个最初的步骤中, Steven 讨论了在创建一个实用工具时要涉及到的内容,如何执行所需的分析,以及如何将分析的结果转换成有用的形式。 第 2 部分:开始启动,从测试开始 Steven 说明了如何通过在开始编写代码之前建立测试计划来节省时间。 第 3 部分:创建高水平的设计 准备开始编程了吗?别着急:您需要先进行设计。 第 4 部分:实施 Codecheck : 构建阶段 该逐步说明您的代码程序包了。 第 5 部分:使参数信息更加灵活 Steven 详细说明了如何消除多层次和以字符串为索引的集合的复杂性。 第 6 部分:构造服务提供程序:具有专门功能的程序包 Codecheck 软件层次结构的低端(相对小型、专门化的单元)一览。 第 7 部分:构造服务提供程序:创建一个通用的报告程序包 了解在您创建 Codecheck 的报告程序包时,如何利用动态 WHERE 子句来优化代码,以及如何为难于操作但却有用的过程添加一个用户友好的包装。 2004 年 1 月在 OTN 上查找最后的 第 8 部分 。为 PL/SQL 构建代码分析实用工具(二)作者:Steven Feuerstein 来源:OTN第一部分:构建一个代码分析实用程序以确保代码首次运行时的流畅和正确 构建实用程序验证代码质量的内部详情许多开发人员和开发经理所面对的一个突出问题就是找到改进代码质量的方法。于是我决定以一种独特的方式来解决这一难题。在随后的几个月中,我将在 OTN 上发布一系列文章说明我是如何构建 Codecheck 的。 Codecheck 是依赖数据字典中的信息,执行重要任务(即分析程序包以检测这些程序包是否包含重载多义性)的一个 PL/SQL 程序包。由于我采用的是自顶而下的设计方法并运用了许多我在 Oracle PL/SQL 最佳实战技巧 中推荐的最佳实战技巧,因此不想只是简单地呈现结果,而更愿意邀请您和我一同演练这一过程。 深入了解这一实用程序要花费一些时间,因为我想借这个机会实际经历一下开发生命周期中的几个阶段。在以后的几个月中,我将进行以下工作: 确定我希望 Codecheck 解决的问题并明确需求。 给出验证实用程序正确运行的测试案例。 研究有助于解决问题的相关技术。 给出实用程序的整体设计(结果发现测试要求会对我的设计产生影响)。 逐步细化以采用易于编写、理解和部署的代码块来构建解决方案。 利用 utPLSQL 单元测试框架自动对实用程序进行复杂的回归测试。 通过对 Codecheck 及其相关概念的学习,您将了解到 Oracle PL/SQL 最新、最好的一些特性,如多层集合。此外,我还将提供一套平台,您可以在该平台上构建和添加自己的 QA 检查,例如检查参数是否太多或太少、查找所有程序包都要用到的程序,并确保代码符合命名规则。也许亲身演练的最大好处在于有机会看到实际运用的一些最佳实战技巧,这可能是学习如何使用这些技巧最简单的方法。 我需要声明一点:我已经完成了 Codecheck 的一个运行版本。我计划一边写下该实用程序的构造经过,一边对其进行改进。因此,该系列每一篇文章的下载都将包含一个 Codecheck (codecheck.zip) 。请随意下载并立即使用。如果您在调试的过程中遇到什么问题,或是有一些改进意见,请发送至 。 确定问题:程序包中的重载多义性 为了写出高质量的程序而顾及到方方面面会令人发疯。因此,我打算集中到几个典型的问题,以免屡屡受挫而不得不放弃创建 Codecheck 的初衷。编写和成功编译包含不可调用程序的 PL/SQL 程序包是极有可能的,而这并没有多大的意义,不是吗?让我们来看看这一奇怪的情形是怎样出现的。 Oracle PL/SQL 支持负载,也就是所谓的 静态多态性 。这就意味着,您能在任何声明段或程序包中用相同的名称定义两个或多个程序,只要这些程序区别显著(通常是参数列表不同),编译器能够辨别您想要使用哪个程序。重载对于提高代码的可用性来说是一项有用的技术。然而,它也会带来一些问题,特别是如果参数列表很长,其中的参数有些有缺省值,有些没有,则尤其如此。 为了向您证实开发人员的确会面临这一问题,我挑选了几个可能会出错的例子,这些例子是以下面所示的程序包说明开头的: CREATE OR REPLACE PACKAGE salespkg IS PROCEDURE calc_total (zone_in IN VARCHAR2); PROCEDURE calc_total (reg_in IN VARCHAR2); END salespkg; / 这一部分在编译时不会有任何问题,正如其程序体一样。其中有两段重载程序,都命名为 calc_total 。其中之一接收一个地段,例如 ZONE 15 ,然后计算该地段的总销售额。而第二个程序则接收一个区域,例如 SOUTHWEST ,然后计算该区域的总销售额。但当我试图调用其中某个程序,却出现一个错误。 SQL exec salespkg.calc_total (ZONE 15) BEGIN salespkg.calc_total (ZONE 15); END; * ERROR at line 1: ORA-06550:line 1, column 7: PLS-00307:too many declarations of CALC_TOTAL match this call 该错误消息明确地指出了这一问题: Too many declarations of CALC_TOTAL match this call. (有多个 CALC_TOTAL 的声明与该调用相匹配)。您可以看到,计算机并不是十分的聪明。您我都可以看出 ZONE 15 是一个地段;难道 PL/SQL 编译器就不能识别出这是 地段 的 calc_total 吗(即带有 zone_in 参数的重载)?不幸的是,编译器并不是这样工作的。 ZONE 15 是字符串的字面意义,编译器无法分析。编译器无法知道应该使用哪段程序,然后就甩手不管了。 我们该如何解决这一问题呢?在这种特定情况下,我可以通过使用指定的参数值来消除多义性: BEGIN salespkg.calc_total (zone_in = ZONE 15); END; 在这个实例,我想要告诉编译器使用特定的参数 ( zone_in ) 。因为这两个重载程序中,只有一个程序的参数名与之相符,这样编译器就知道该调用这两个中的哪一个了。尽管如此, 不得不 使用参数名引用来调用一个过程或一个函数还是令人难以接受。这明显是一个糟糕的设计 而且会越来越糟。考虑下面的程序包说明: CREATE OR REPLACE PACKAGE salespkg IS PROCEDURE calc_total (zone_in IN VARCHAR2); PROCEDURE calc_total (zone_in IN CHAR); END salespkg; / 同样,这个程序包在编译时也不会有任何问题。但现在又面临另一种情况:无法调用这些过程中的任意一个。他们共享程序名和参数名。唯一的区别就是数据类型。 VARCHAR2 当然不同于 CHAR ,因此编译器会让您轻松过关。但不幸地是,这两种数据类型的差异性还不够大,这将导致在真正试图使用代码的时侯出现难题。考虑下面的一段代码: BEGIN salespkg.calc_total (ZONE15); END; ZONE 15 是固定长还是可变长? PL/SQL 文档中说道 All string literals except the null string () have datatype CHAR , (所有非空串的字符串文字都是 CHAR 型)但是编译器并没有意识到这个问题。非常奇怪,即使向程序传送了一个显式声明为固定长度的字符串,仍然会出现问题。 SQL DECLARE 2 l _zone CHAR(6) := ZONE15; 3 BEGIN 4 salespkg.calc_total (l_zone); 5 END; 6 / salespkg.calc_total (l_zone); * ERROR at line 4: PLS-00307:too many declarations of CALC_TOTAL match this call 如您所见,确实可以定义这样一个程序包重载,即它可以顺利通过编译,但要么不可用,要么只能通过 非自然行为 使用,例如强制使用参数名引用。 我将采用什么样的解决方案呢? 为了识别这些重载问题,我产生如下的想法:也许我可以构建一个实用程序 自动 扫描程序包,检查所有可能的有效程序调用置换,并提醒我注意那些多义重载。我能够作到这一点吗?看起来我应该要能够将程序包定义解析为各段程序,同时解析出每个程序的参数列表。我应该能够取出这些参数的数据类型和缺省值。我如何才能获得这些信息呢?遗憾的是,我对 PL/SQL 解析器没有 API 级的访问权限,特别是不能从 PL/SQL 自身内部来进行访问。而且我压根不想 考虑 自己编写一个解析器。那么一个积极的(深受困扰的)实用程序构造者会如何去做呢?他会查找可以替代的方法。 还有没有其他的方法可以从程序中提取这一信息呢?我想起每当我编译一个 PL/SQL 程序, Oracle 数据库就会对源代码进行解析并将其装载到数据字典中。然后就可以提供各种数据字典视图给出对所存储代码的不同描述。 ALL_SOURCE 揭示了源代码。 ALL_DEPENDENCIES 显示各个对象之间的依赖性。 ALL_OBJECTS 告诉我哪个程序是 INVALID 。也许有某个数据字典视图有助于解决这一问题。我该如何找到它呢?数据字典中有很多视图,而且这些视图都非常晦涩。 为了能对此有所帮助,我构建了一个名为 dd_view_scan 的实用程序,该程序可以找到符合需要的那些视图。使用 dd_view_scan ,我可以轻松搜索视图集以便找到那些可能会提供帮助的数据源。接下来我会对某个特定的视图进行深入分析,看看它是否真的包含我所需要的信息。例如,如果我希望分析程序的重载,那么我就不仅需要知道程序名,还需要检查参数列表(也就是传递的参数)。首先我会向 dd_view_scan 查询含有单词 parameter 或 argument 的那些数据字典视图。(注意:我使用 Oracle9 i Release 2 得到这些结果。使用早期版本运行相同的查询可能会得到不同的结果。) 仔细检查该列表, ALL_ARGUMENTS 引起了我的注意。其他的参数看起来要更具针对性,不是我想要的那种。当我仔细分析该参数,我找到了程序包名、参数名和数据类型。这些看起来就比较接近我的目标,有必要深入查看一下。让我们继续进行探讨。 研究:有关 ALL_ARGUMENTS 的全部内容 下一步,查看 Oracle 文档集。我急切地去查看 Oracle9 i 文档,希望能从中找到答案。我从浏览器中打开文档,使用 Master Index ,立即缩小了 ALL_ARGUMENTS 的范围。使用下面的查询,您可以顺便获得虽不相同但还相近的信息(参见 all_arguments_cols.sql ): SELECT column_name, comments FROM all_col_comments WHERE table_name=ALL_ARGUMENTS 遗憾的是,您在 表 1 中所见的就是 Oracle 可提供的所有信息。无论如何,我们已经迈出了第一步。许多列的引入都是不言而喻的。而对于其他的,例如 OVERLOAD 、 POSITION 和 DATA_LEVEL ,就不太清楚了。 下面,我需要确信我已经理解了 ALL_ARGUMENTS 的内容。我还必须证实 ALL_ARGUMENTS 包含了 Oracle 所说的它包含的东西。如果您研究 Oracle 技术超过六个月,那么您就会明白任何事都不能想当然。文档中对某技术有某种说法,并不意味着该技术本身就是那样的。某个作者(例如 Steven Feuerstein )说某技术能够在其笔记本电脑中 Windows 2000 下的 Oracle9 i Release 2 上运行,并不意味着该技术在 您的 系统中也会以同样的方式运行。自己进行测试来验证取决于您的应用程序的那些操作是非常重要的。 下面就是我所作的一些工作:我将名为 allargs_test 的程序包(位于 all_arguments.tst 文件中)放在一起。该程序包定义了一个带有子程序的包,这些子程序含有各种不同的参数组合(或者没有),这些参数会用到大量不同的数据类型、参数模式等。 然后,我又构造了一些查询以检查 ALL_ARGUMENTS 必须向该程序包提供哪些信息。可以在 allargs*.sql 脚本中找到这些查询。为了让您能够看到 ALL_ARGUMENTS 内容,我会回顾这些查询的某些结果。随后我将提供一个发现结果列表,该列表将引导我设计和实现 Codecheck 。 假如有一个带有下列说明的程序包: CREATE PACKAGE allargs_test IS PROCEDURE difftype1; FUNCTION difftype1 RETURN VARCHAR2; END; 那么这些程序的 ALL_ARGUMENTS 内容将是如下所示: Core ALL_ARGUMENTS Info for allargs_test.difftype1 OVLD ARGNAME POS SEQ LVL TYPE DEFVAL IN_OUT - - - - - - - - 1 1 0 0 IN 2 0 1 0 VARCHAR2 OUT 通过该结果,我得出以下结论: 如果该程序是重载的,则 OVERLOAD 列(在上面的例子中简称为 OVLD )表明这是第 N 个重载;否则该列为 NULL 。 当某个过程没有参数, ALL_ARGUMENTS 会包含一个位置为 1 而序号和层次均为 0 的一行。 当某个函数没有参数,就 不会 有这样一个特殊行。与此不同,它仅有一行描述 RETURN 子句,其中位置为 0 。 RETURN 子句的 argument_nameRETURN 为 NULL 。 现在来看一下 表 4 ,该表在 ALL_ARGUMENTS 中显示了一些描述过程 composites 的行,这些行里装载的全部是简单的、或复合的数据类型,例如记录或是集合(参阅 all_arguments.tst 获得每一类型的完整定义): CREATE OR REPLACE PACKAGE allargs_test IS PROCEDURE composites ( account_in NUMBER, person person%ROWTYPE, multirec myrec3, num_table number_table, recs_table myrec_table); END; 在分析这些信息后,我得出以下结论: 层次显示的是参数列表中的嵌套层数。所有真正出现在参数列表中的参数层次都为 0 。如果某个参数是一个复合参数,则该复合参数中的每一个元素(例如每一个记录的字段)在 ALL_ARGUMENTS 显示的层次就为 1 ,依此类推。 位置和层次的组合对于给定程序的 ALL_ARGUMENTS 行 不是 唯一的,即使在单一重载内也是如此。但是,位置和层次的组合对于某个给定的 0 层 参数 (参数列表中实际显示的参数)却是唯一的。 由于能够在其他复合参数中声明如集合和记录这样的复合参数,而且对嵌套层数没有限制, ALL_ARGUMENTS 的内容可能会变得非常复杂。 数据类型字段只显示 通用 类型,例如 PL/SQL RECORD ,但并不显示实际的类型。为此,我需要进一步深入研究一下 ALL_ARGUMENTS 的 TYPE_* 列。 表 5 显示了下列程序的 ALL_ARGUMENTS 的内容: CREATE OR REPLACE PACKAGE allargs_test IS PROCEDURE oneargdef ( onearg IN VARCHAR2 := NULL); PROCEDURE oneargdef ( onearg IN CHAR := abc); END; 在此例中,我费了一些功夫发现了一个有趣的现象:即使 ALL_ARGUMENTS 声称 显示了参数的缺省值,但实际上,这一列常常是 NULL 。 只有 当您超出文档的范围探讨,并对 Oracle 技术的实质进行研究,才会发现这类问题。 最后,让我们来看看所有的 TYPE_* 列中有些什么内容。我使用 allargs3.sql 来显示非 NULL TYPE_NAMEs 的参数。您可以在 在 表 6 中看到 复合参数 的输出。这是一个很有用的信息。如果我只依赖 DATA_TYPE 列的值,我能看到数据类型是 PL/SQL 表,但是只要我查看一下 TYPE_SUBNAM 列,就可以知道该表是 哪种 类型。 总结如下:一方面, ALL_ARGUMENTS 看起来很有用。它提供了有关参数的大量有用信息。另一方面,它又似乎缺少了某些可以呈现参数缺省值的关键信息。没有这一信息,我只能对重载进行基本的分析(该程序是否含有相同个数和相同类型的参数?)。我不能报告出那些在调用中使用参数子集(且尾随缺省参数被省略)时可能会有多义性的被重载程序,但我希望我的实用程序能够处理这一复杂情况。下一步,我将试图通过其它方式来获得这一信息。 使用提供的程序包如何? 我已经查看过数据字典的视图集。 Oracle 还提供哪些其他的预建工具?考虑到我曾参与共同编著一本书(名为 Oracle Built-in Packages ),我很自然地就想到了寻找一个能提供帮助的、内置的或 提供的 包( Oracle 术语)。 查看 ALL_OBJECTS 寻找感兴趣的程序包: SQL SELECT * 2 FROM all_objects 3 WHERE owner = SYS 4 AND object_name LIKE %ARGUMENT% 5 AND object_type = PACKAGE; no rows selected 什么也没找到。下面,我要扫描 ALL_SOURCE ,在提供的程序包的源代码中搜索如 argument 和 parameter 这样的单词。实际上,我只能查看程序包说明,因为程序包的程序体是封装起来的(一种粗略的且只能取得部分成功的加密形式)。此外,每当考虑运行这些查询时,必须注意,有些查询会持续 很长 时间,因为 ALL_SOURCE 通常包含了大量的行(我当前所用的有 111,782 行)。 因此,我组合了另一个小的实用程序 dd_source_scan 过程(在下载的 ddsourcescan.sp 文件中查找该实用程序) 来确保我能够尽可能有效地运行查询。我希望能找到所有包含数据字典视图名 ALL_ARGUMENTS 的数据字典视图。 BEGIN dd_source_scan ( %, all_arguments); END; 不幸的是,通过关键字检索该扫描返回了 0 行。下一步的策略是要放宽查找条件,查找包含单词 arguments 的程序包说明: BEGIN dd_source_scan ( %, arguments); END; 啊!这一次返回了很多线索,其中的一部分显示在 表 7 中。 DBMS_DESCRIBE 很可能就是我要找的。 查看文档,我找到: The procedure DESCRIBE_PROCEDURE accepts the name of a stored procedure, a description of the procedure, and each of its parameters. ( DESCRIBE_PROCEDURE 过程接收某个存储过程的名称、有关该过程的描述和每个参数)。我必须承认这确实有点令人困惑。它是否要接收全部这些内容?而且在接收完之后又能向我提供什么呢?遗憾的是,我所看的这部分文档实在是描述得太简单了,这意味着我后来花费了大量的时间来研究 DBMS_DESCRIBE.DESCRIBE_PROCEDURE 的操作和特性。正如您随后会在这一系列文章中发现,我将我所学到的有关这一程序的所有知识都加以吸收,并将这些知识缓存到一个单独的程序包中。 这个时候,我想要查看 DBMS_DESCRIBE 和 ALL_ARGUMENTS 的一些差异,并想要通过此举从侧面了解这些差异会对我的实现产生什么样的影响。例如,这一过程通过使用一系列 PL/SQL 集合将有关其所有参数的信息传递回来,从而返回 对过程的描述 。这些集合的内容大致地反映了某个 ALL_ARGUMENTS 查询检索到的数据,但是非常奇怪(也许您不觉得),每一个集合都经过不同的路由,最后到达的地方也略有差别。 如果您发现尽管 ALL_ARGUMENTS 向您提供了数据类型名(例如 VARCHAR2 或是 OBJECT ),但 DBMS_DESCRIBE 返回的实际上是一个整型代码,那么您就会就非常清楚它们之间的差异。总之, DBMS_DESCRIBE 在很大程度上都依赖于整型码,而 ALL_ARGUMENTS 将这些码转换为描述性的字符串(这一点意义重大,因为它是一个可以让您看到程序参数信息的数据字典视图)。 为 PL/SQL 构建代码分析实用工具(三)作者:Steven Feuerstein 来源:OTN第二部分:从测试开始 在编写代码前建立一个测试计划,可以节省您的时间。 在本系列的 第一篇文章 中,我决定构建一个可以对代码进行质量检查的实用工具:特别是识别 PL/SQL 程序包中具有歧义或者潜在歧义的超载问题。 此外,我还识别数据源( ALL_ARGUMENTS 数据字典视图)和代码( DBMS_DESCRIBE 程序包),以帮助构建实用工具。下一步要做什么呢? 坦率地说,我自然倾向于打开我所喜爱的集成开发环境 (IDE) 并开始动指如飞地编写代码,投入激动人心的创作之中。我希望在工作时思考并得出结论,不断地应对挑战,使工作成果运行起来,然后对其进行微调。 这种方法有积极的方面(您当然不会有过度设计的风险),但也有很多缺点。首先,如果我所使用的构建方法是直通式构造非线性系统 常被亲切地称为 HRCLS 或 Hercules (一种 非常 轻型的方法论),我最终不会仅是微调代码。绝对不会,在我将范围缩小到最终目的、目标和实质内容时,我最终将会以重写整个程序 一次、两次或三次。但是,尽管可以激动地看到,经过自己的努力,实用工具成形、进步并改观,但这会浪费很多的时间。 对于 Codecheck ,我会忍住最初的诱惑。我不会在项目开始的头 60 秒内就编写代码,而是做一个简单的声明:我保证使我编写的代码适用于一个全面的测试计划。 这与避免 Hercules 综合症有什么必然的关系呢?让我们来考虑这种保证的含义: 我将制订一个测试计划,它非常全面,精心策划了数十个(甚至可能有 100 个之多)测试方案,包括参数的数量、各种数据类型的结合以及缺省值的有无。 我要设计、构建和运行测试,这些测试可确定我的代码是否满足测试计划的要求:换言之,设计、构建和运行涵盖我的全部测试方案的测试。 天哪,这听起来确实很有道理,不是吗?我的意思是,谁 会 一直做所有的这些事情?况且,我们都知道这样的事实:我们之中很少有人实际上会花时间,或在手边有必备的工具去做全面的测试。实际上我认为,世界上至少百分之九十的软件开发人员和开发团队(包括我自己)远远不会完全按上述保证去做。 对我来说,在开发初始时我表明要执着地进行测试,我发现这一点促使我实现了 Codecheck 。 定义范围,做出假设 在开发一项测试策略并构造测试之前,我需要确定项目的使用范围。用户群通常确定(并经常更改)项目的使用范围。对于 Codecheck 以及我制作的很多其他实用工具,您,开发人员,是我的用户,但我仍然需要确定使用范围,把您的需求作为我的指导。我的目标是产生一个代码体,能立即帮助开发人员提高代码质量,但也可以作为一项稳定而且可扩展的功能,开发人员可以将其加入代码中满足自己的需要。它必须能够处理现实世界中足够的复杂性,这样才有用处,但又不可太复杂,以至于将 Codecheck 开发变成一种全职工作。 当我深入查看 ALL_ARGUMENTS 的内容时,我吃惊地发现那些参数列表会变得非常复杂。例如,在 Oracle9 i 的环境中,一个参数可以将记录的结合数组(以前称为表的索引)作为其类型,其中记录的一个字段是另一个结合数组,以此类推。非常坦率地说,我实际上不希望必须编写代码来处理这些参数全部的可能情况。 与此相反, Codecheck 将只基于 “0 级 ” 参数来检查和进行分析:这是指在 ALL_ARGUMENTS 视图中的那些项目,当其出现在程序头时,它们对应于参数列表。实际上,这可能是您为分析超载而 所需 的全部要素,但是全部的详细资料可能在进行某种其他的代码检查时派上用场。(在撰写此文章时,我已确定了一种需要更多信息的情况:如果您将一个参数定义为表单 %ROWTYPE 的记录,则 ALL_ARGUMENTS 和 DBMS_DESCRIBE 都不会提供其类型的信息。您可能必须比较那些行类型( 1 级或更多级)的 各个字段 的数据类型以识别岐义。天哪。 定义测试策略 开发 Codecheck 的下一步是探究和定义测试策略。我曾提到过,我承诺编写能够满足测试计划的代码,这种承诺影响着开发过程。例如,我在编写如 Codecheck 等实用工具时的第一个冲动是,制作一个程序,接受一个程序包的名称并在屏幕上显示代码检查的结果。为了确定实用工具是否正确工作,我需要查看屏幕上的检查结果并对其进行分析。这听起来如何?熟悉吗?可伸缩吗?通常这种方法甚至对非常简单的程序都无效。 Codecheck 测试计划无疑会有很多测试方案,而其结果并不明确。换言之,除非我记住成功对所有这些测试方案意味着什么,否则我必须依靠手动的、直观的验证(先看这个窗口;然后将其与那个窗口的内容进行比较)。我需要用很长的时间完成一项测试(这是构成责任性的一项相当重要的要素),所以我很少进行测试 如果曾做过测试的话。这与我的保证相违背。 我需要找到一种更快捷方便的测试方法。使用 Java 的许多开发人员转向 Junit 。 PL/SQL 开发人员则利用 utPLSQL ,一种用于 PL/SQL 开发人员的开放源单元测试框架。(申明:我是 utPLSQL 的创建者,尽管其他人现在也帮助进行实施并制作文档。) 我不会在本文中以很大的篇幅详细描述 utPLSQL 的起源、理论基础或基本工作方式。如果您需要了解比本文内容更详细的情况,请访问 / 或 http:/utplsql.oracledeveloper.nl 。 utPLSQL 简介 utPLSQL 是一种用于 PL/SQL 程序的测试框架(代码以及使用这种代码的进程的集合)。使用 utPLSQL ,您可以构造包含单元测试过程的单元测试程序包,并依照 utPLSQL 的命名规范和测试机制来设计此程序包。然后您只须简单地操作 utPLSQL 来测试程序或程序包。它运行所有测试并自动检测该测试是否成功或失败。它准确指出失败的测试方案,使您更快地确定正确的测试方案并识别应用程序中错误的原因。 这种框架是基于极限编程的单元测试概念 ( ) 以及 Junit ( Java 单元测试框架)。下面是一些该方法进行单元测试的基本原则: 在编写代码前编写单元测试。 少做编写和更改,多做测试。 自动执行测试和生成报告:红绿灯式的方法。 图 1 表示 utPLSQL 体系结构的一个简化视图,它是以强大有效的方式自动执行测试的一个往返旅程。下面对行程中的各站作一解释: 1. 调用 utPLSQL 测试过程执行测试程序包。 utPLSQL 按照动态 PL/SQL 和命名规范来运行任何设置代码,定位并执行单元测试程序,并进行必要的清除( “ 拆卸 ” 步骤)。 2. 单元测试过程调用 “ 判断 API” ,它将测试结果与 “ 控制 ” 条件进行比较。 3. 判断程序将结果(通过或失败)写到下面的结果表中。 4. tPLSQL 测试读出结果表中的内容,确定该测试的状态。 5. utPLSQL 根据结果作出报告,或者通过 DBMS_OUTPUT 送到屏幕,或者通过 UTL_FILE 送到一个文件。 图 1 : utPLSQL 体系结构的往返旅程简化视图 .ppt. 让我们来看一个很简单的示例,从而大致了解单元测试程序包的内容。假设我已经创建了一个关于 SUBSTR 的封装,允许在开始和结束点之间请求一个子串(一个简单的函数)( 列表 1 )。 即使是简单的或看似不重要的程序(如 betwnStr )也需要测试 而实际上我必须考虑大量的测试方案(包括 NULL 开始值、 NULL 结束值以及开始大于结束等)。 列表 2 显示了测试程序包的一部分(全部测试包的内容请参见 ut_betwnstr.pkb )。关于关键部分的解释,请参见 表 1 。 也许您会想, “ 多么单调乏味!我真的必须编写所有那些代码,只是为了测试这个简单的函数吗? ” 实际上,那些在测试领域工作的人都知道,测试一个应用程序所需要编写的代码数量常常比应用程序本身更多。对于这个特定的程序包和测试代码的 utPLSQL 风格,您在某些情况下会生成全部的测试代码。实际上, ut_betwnstr 程序包 通过 对 utGen.testpkg_from_string 过程的调用而生成, 如列表 3 所示 。 即使您不生成测试程序包,也经常可以找到其他方法,利用最少的代码运行许多基于 utPLSQL 的测试 这正是我用 Codecheck 所做的工作。 将 utPLSQL 应用于 Codecheck 要利用 utPLSQL ,我需要构建一个单元测试程序包并调用 utAssert 程序,以确定我的代码是否通过其测试。但是,在进行这些操作之前,我需要精心制作我的测试方案。请记住:测试方案第一,其次才是代码。 现在应该寻找灵感,暂停前进,考虑一下我所提供的实用工具。我希望它能够验证什么?那些能编译但包含歧义超载的程序包的特例是什么?我能检测到什么情况?有效超载的示例是什么?毕竟我需要测试正面和负面的因素。经过一段时间以后,我给出以下的内容: 有效的超载 两个超载程序带有不同数量的非缺省参数。 两个超载程序带有相同数量的非缺省参数,并在数据类型方面具有足够的差别(如 NUMBER 对 DATE )。 函数和过程具有相同名称和参数列表,包括不带参数的情况。区分这两者并没有问题,因为它们在代码中的使用方法不同。 无效的超载 两个超载程序具有不同数量的非缺省参数,导致歧义的参数列表。 两个程序具有单个参数,数据类型相同但参数名不同。 两个程序具有相同的名称,具有单个参数,但却是同系列中不同的数据类型。 一个程序没有参数,第二个程序具有一个带缺省值的参数。 一个程序具有 N 个参数,第二个程序具有 N+1 个参数,全部带有缺省值。 一个程序具有 N 个参数,其中 N-1 个参数有缺省值;第二个程序具有 N+1 个参数,其中最后两个缺省。 一个程序具有一个参数,第二个程序具有两个参数,其第二个参数有缺省值。 我肯定还将考虑其他测试方案,但这些已足够继续进行了。如何最好地进行上述方案的测试?我需要在程序包中定义这些不同的结合。让我们称之为 allargs_test 。为每个测试方案使用一个不同的超载程序名称,可能效果会较好。这样可以保持事情清晰易辨而且非常有条理。实际上,我要创建一个表(参见 表 2 )。 此表有助于工作但还不够。我还需要为这些测试方案分别指定期望的结果。它是有效的超载吗?如果不是,它是如何失败的?我如何用一种能使用 utPLSQL 自动运行测试的方式来获取这种信息?问题太多了。 在本文中,我没有指定所有测试方案的结果全集;我认为大致了解全部过程就足够了。让我们完整地运行 表 2 中的一些方案,从而了解我需要测试哪些信息种类。考虑 samefamily1 过程。以下是这一超载的详细说明: CREATE OR REPLACE PACKAGE allargs_test IS PROCEDURE samefamily1 (arg IN NUMBER); PROCEDURE samefamily1 (arg IN INTEGER); 很清楚, arg 参数的数据类型太相似了,它们都属于数字型。因此,这将是导致故障的歧义超载。对 samefamily1 运行 Codecheck 的结果应该类似于: allargs_test.samefamily:invalid overloading 结果看来是很基本的东西。我们只须说是或不是吗?或者说无效或有效?在本例中,我想是这样的。但我们再来看另一个更有趣的情况。考虑 noparms2 的开头部分: CREATE OR REPLACE PACKAGE allargs_test IS PROCEDURE noparms2 ( arg 1 IN VARCHAR2 := NULL, arg 2 IN VARCHAR2 := NULL); PROCEDURE noparms2 ( arg 1 IN VARCHAR2 := NULL, arg 2 IN VARCHAR2 := NULL, arg 3 IN VARCHAR2 := NULL); 关于这两个程序, Codecheck 会告诉我什么呢?让我来计算可能引起 allargs_test.noparms2 无效或歧义的方式: 1. allargs_test.noparms2; 2. allargs_test.noparms2 (abc); 3. allargs_test.noparms2 (abc, def); Codecheck 应该识别 noparms2 的总共三种不同的无效形式。这是由于所有的跟踪缺省值允许我使用不同数量的参数来调用 noparms2 。这比第一个测试方案复杂得多。当然,它可以变得更加复杂,这取决于超载程序的数量、参数的数量以及缺省值的有无。 我如何使用 utPLSQL 检查上面所示结果的种类 自动检查吗?测试框架提供各种各样的判断程序。例如,我可以检查两个标量值是否相等,这一点您在 betwnstr 中已经看到: utassert.eq (zero start, check_this, against_this); 但是,我还可以进行更有趣的判
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年工业机器人运维维修服务绿色物流案例
- 2025年家庭影院装饰画声学设计
- 护理诊断的案例研究
- 2026年山西省中考英语一模试卷(含答案)
- 智能体构建与应用开发(Python+LangChain)(微课版)课件全套 项目1-8 认识大语言模型和智能体- 部署和发布智能体
- 选矿集控工保密强化考核试卷含答案
- 幻灯机与投影机维修工安全技能测试强化考核试卷含答案
- 道路巡视养护工复试模拟考核试卷含答案
- 2026年新科教版高中高二物理下册第一单元交变电流综合计算卷含答案
- 洗衣师安全生产规范考核试卷含答案
- DB45∕T 2362-2021 城镇排水管渠运行维护技术规程
- 呼吸机相关肺炎院感防控体系构建
- 大健康连锁店商业计划书
- 2024广西金融职业技术学院辅导员招聘笔试真题
- 井下煤矿爆破方案(3篇)
- 校园消防设施改造项目可行性研究报告
- JG/T 252-2015建筑用遮阳天篷帘
- CJ/T 511-2017铸铁检查井盖
- 幼儿园项目式课程教学培训
- 【高考真题】贵州省2024年高考生物试卷(含答案)
- 《装配式建筑概论》考核试题及答案
评论
0/150
提交评论