如果喜欢,可以在SYSTEM模式下创建utPLSQL,这样不需要创建一个新用户。但是,你可能更喜欢在一个单独的模式下进行。以下是Bill Pribyl提交的一个示例脚本,它创建了一个用户“UTP”,拥有安装utPLSQL所需的足够权限。connect system/manager
create user utp identified by utp default tablespace
users temporary tablespace temp;
grant create session, create table, create procedure,
create sequence, create view, create public synonym,
drop public synonym to utp;
alter user utp quota unlimited on users;
注释:如果该模式没有创建与删除公共同义词或者执行DBMS_PIPE包的权限,将会获得一些错误信息。但是utPLSQL仍然能够使用。
一旦连接到该模式,运行ut_i_do.sql文件,加上参数“install”,安装全部utPLSQL对象。你必须确认SQL*PLUS会话的工作目录与utPLSQL文件目录相同,然后提交以下命令:
SQL> @ut_i_do install
该文件将会创建所有的表、包以及其他所需的对象。注意,安装脚本将会使用SPOOL命令动态创建一些文件。因此,你需要拥有该目录下的写权限。
查看ut_i_do.log文件检验utPLSQL的安装。
删除utPLSQL
要删除该产品,再次运行ut_i_do.sql脚本,加上参数“uninstall”,命令如下:
SQL> @ut_i_do uninstall
2.2、选择程序进行测试并确定测试用例
你可能想要测试一个独立的过程或函数、或者一个包中的一组程序。挑选程序并提出一组不同的用例。这些将会决定你运行的测试种类与数量。
例如,假设我已经创建了一个独立的函数betwnStr(一个SUBSTR函数的变形,基于开始位置与结束位置返回一个字串),存储在Examples目录的betwnstr.sf文件中。
CREATE OR REPLACE FUNCTION betwnstr (
string_in IN VARCHAR2,
start_in IN INTEGER,
end_in IN INTEGER
)
RETURN VARCHAR2
IS
l_start PLS_INTEGER := start_in;
BEGIN
IF l_start = 0
THEN
l_start := 1;
END IF;
RETURN (SUBSTR (string_in, l_start, end_in - l_start + 1));
END;
/
为了测试该函数,我将会使用各种不同的参数,如下表所示:开始位置
结束位置
结果
NULL
NOT NULL
NULL
NOT NULL
NULL
NULL
NULL
NULL
NULL
3(正数)
1(更小的正数)
NULL
3(正数)
100(大于字符串长度)
从第3个位置开始的字串
2.3、创建一个测试包
utPLSQL提供了一个简单、自动化的方式运行测试。然而,要想自动化运行,必须遵从一些规则,以便utPLSQL能够找到并执行你的测试代码。这些规则包括:
测试代码必须位于一个测试包内。
测试包的规范应该以文件名ut_.pks存储,包体必须以文件名ut_.pkb存储(遵从该命名约定,utPLSQL可以设置为每次测试前自动重编译测试包)。
测试包必须包含一个设置过程ut_setup以及一个清除过程ut_teardown,都没有任何参数。
测试包需要为每一个被测试程序编写一个单独的过程。
现在,你应该知道utPLSQL包含许多额外功能,允许你修改许多默认值(例如用于设置、清除以及测试过程的前缀)以及utPLSQL包的行为。此时先不进行详细讨论。
因此,如果我要测试这个独立的过程betwnstr,我的测试包规范将会如下所示,它存储在文件ut_betwnstr.pks中:
CREATE OR REPLACE PACKAGE ut_betwnstr
IS
PROCEDURE ut_setup;
PROCEDURE ut_teardown;
-- For each program to test...
PROCEDURE ut_BETWNSTR;
END ut_betwnstr;
/
现在,让我们创建包体,存储在文件ut_betwnstr.pkb中。在这个简单案例中,我不需要设置任何数据结构,而且不需要清除任何东西。我的清除程序可以为空(但是必须存在)。因此,前半部分为:CREATE OR REPLACE PACKAGE BODY ut_betwnstr
IS
PROCEDURE ut_setup IS
BEGIN
NULL;
END;
PROCEDURE ut_teardown
IS
BEGIN
NULL;
END;
接下来创建单元测试过程。我需要回顾测试用例表格并将它们转换为对utAssert包中程序的调用。
utAssert提供了许多“断言例程”来测试传入的值或表达式并记录结果。你可以使用它测试两个字符串、文件、表或者集合的相等性。你可以测试表达式结果是否为NULL。
对于每个测试用例,我提供了一个该用例的字符串描述,以及一个表达式。从“typical valid usaege”开始,我传入了一个字符串“abcdefg”,开始位置3以及结束位置5,而betwnstr应该返回“cde”。
PROCEDURE ut_betwnstr IS
BEGIN
utAssert.eq (
'Typical valid usage',
BETWNSTR(
STRING_IN => 'abcdefg'
,
START_IN => 3
,
END_IN => 5
),
'cde'
);
我调用了utAssert.eq,因为我想要比较betwnstr返回值与字符串“cde”。它们应该相等。
现在我可以编写其他用例的程序。
utAssert.isnull (
'NULL start',
BETWNSTR(
STRING_IN => 'abcdefg'
,
START_IN => NULL
,
END_IN => 5
)
);
utAssert.isnull (
'NULL end',
BETWNSTR(
STRING_IN => 'abcdefg'
,
START_IN => 2
,
END_IN => NULL
)
);
utAssert.isnull (
'End smaller than start',
BETWNSTR(
STRING_IN => 'abcdefg'
,
START_IN => 5
,
END_IN => 2
)
);
utAssert.eq (
'End larger than string length',
BETWNSTR(
STRING_IN => 'abcdefg'
,
START_IN => 3
,
END_IN => 200
),
'cdefg'
);
END ut_BETWNSTR;
END ut_betwnstr;
/
至此,已经创建了用于betwnstr函数的单元测试程序。编译这两个文件,确认没有编译错误。SQL> @ut_betwnstr.pks
Package created.
SQL> @ut_betwnstr.pkb
Package body created.
接下来就是运行测试了。
2.4、运行测试
启动SQL*PLUS并以被测试代码拥有者的模式连接,也就是UTP。然后调用utPLSQL.test运行测试包。SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)
第二个参数,“recompile_in => FALSE”,说明已经编译了测试包,不需要重编译。
如果测试没有发现任何错误(断言程序没有检测到),将会看到以下输出:SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)
SUCCESS: "betwnstr"
如果测试检测到了失败,将会显示类似以下输出:SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)
FAILURE: "betwnstr"
BETWNSTR: IS NULL: NULL start
BETWNSTR: End larger than string length; expected "cdeg", got "cdefg"
至此,已经完成安装utPSQL,编写一个测试包并运行测试。
测试包自动重编译
utPLSQL默认会尝试重编译你的测试包代码(包规范必须位于.pks,包体必须位于.pkb)这些文件必须位于数据库所在的机器上。可以调用utConfig.autocompile关闭此功能。utConfig.autocompile(false);
如果想要使用该功能,utPLSQL需要使用UTL_FILE包读取源代码文件并编译这些代码。使用UTL_FILE前需要进行配置,参见下文。配置之后,必须调用utConfig.setdir通知utPLSQL测试包的存储位置。否则,utPLSQL将不能重编译测试包,而是显示一个错误信息。
假设将代码存储在E:\utplsql\testall中,使用以下调用:SQL> exec utConfig.setdir ('e:\utplsql\testall')
2.5、关于模式的注释
在2.1中描述了拥有组成utPLSQL框架的对象的用户。然而,总是存在一些关于哪个模式应该包含测试包以及连接哪个模式运行测试。可以使用不同的方式,但是最简单的方式如下:任何模式都可以拥有utPLSQL,只要其他用户能够访问到它。
测试包应该位于与被测试代码相同的模式下。
应该连接到测试包的模式下运行测试,也就是被测试代码的模式下。
2.6、下一步
要了解utPLSQL更多不同特性和功能,查看用户指南。
要想更深一步了家如何构建测试包,查看如何构建测试包。
更多构建测试用例与不同类型的测试包示例,查看示例文档。
3、管理主题
3.1、配置UTL_FILE
如果想要utPLSQL自动重编译测试包,必须数据库启用了UTF_FILE(它允许读写操作系统文件)。数据库初始化参数文件必须至少包含一个utl_file_dir参数。utl_file_dir =
也可以通过alter system命令设置spfile,修改该参数需要重启数据库实例。
一些使用建议
访问不能递归到子目录。如果设置了以下参数:utl_file_dir = c:\group\dev1
utl_file_dir = c:\group\prod\oe
utl_file_dir = c:\group\prod\ar
不能使用UTF_FILE打开c:\group\prod\oe\reports目录中的文件。
不要在目录最后加上分隔符,如Unix中的斜线。以下设置将会导致读写文件时出现问题:utl_file_dir = /tmp/orafiles/
测试UTF_FILE存取
使用以下代码(修改目录名和文件名之后)验证UTF_FILE能够正确读取文件。
SET SERVEROUTPUT ON
DECLARE
fid UTL_FILE.FILE_TYPE;
v VARCHAR2(32767);
PROCEDURE recNgo (str IN VARCHAR2)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE ('UTL_FILE error ' || str);
UTL_FILE.FCLOSE (fid);
END;
BEGIN
/* Change the directory name to one to which you at least
|| THINK you have read/write access.
*/
fid := UTL_FILE.FOPEN ('e:\demo', 'existing_file', 'R');
UTL_FILE.GET_LINE (fid, v);
dbms_output.put_line (v);
UTL_FILE.FCLOSE (fid);
fid := UTL_FILE.FOPEN ('e:\demo', 'new_file', 'W');
UTL_FILE.PUT_LINE (fid, v);
UTL_FILE.FCLOSE (fid);
EXCEPTION
WHEN UTL_FILE.INVALID_PATH
THEN recNgo ('invalid_path');
WHEN UTL_FILE.INVALID_MODE
THEN recNgo ('invalid_mode');
WHEN UTL_FILE.INVALID_FILEHANDLE
THEN recNgo ('invalid_filehandle');
WHEN UTL_FILE.INVALID_OPERATION
THEN recNgo ('invalid_operation');
WHEN UTL_FILE.READ_ERROR
THEN recNgo ('read_error');
WHEN UTL_FILE.WRITE_ERROR
THEN recNgo ('write_error');
WHEN UTL_FILE.INTERNAL_ERROR
THEN recNgo ('internal_error');
END;
/
它会读取并显示E:\demo中existing_file文件中的第一行,然后将该行写入一个新建的文件new_file中。