sql developer内置单元测试框架支持pl/sql对象测试,需按步骤指定对象、执行启动/结束处理、运行测试并设置验证规则;常见错误包括表不存在、参数类型不匹配及缺少断言,正确做法是右键创建测试模板、在setup中初始化数据并commit、主体调用目标过程、expected result栏定义验证逻辑、teardown中清理数据。

用 SQL Developer 内置测试框架写单元测试
SQL Developer 自带的单元测试功能足够覆盖大多数日常场景,不用额外装 utPLSQL。关键不是“能不能测”,而是“怎么让测试跑起来不报错”。
常见错误现象:ORA-00942: table or view does not exist(测试里引用了未授权访问的表)、ORA-06550(参数类型不匹配)、Test case failed: no assertion defined(忘了加验证逻辑)。
- 右键存储过程 → “Unit Test” → 选“Create Unit Test”生成模板,别点“Test”——那是调试,不是单元测试
- 启动处理(Setup)里写初始化语句,比如
INSERT INTO employees2 VALUES (999, 'TEST', 'EMP', 5000, NULL, SYSDATE, 'IT_PROG', NULL, NULL, 10, NULL);,记得COMMIT; - 测试主体必须调用目标过程,例如
AWARD_BONUS(999, 12000);;输出参数要显式声明变量接收,不能只传空值 - 验证规则必须写在“Expected Result”栏,比如
SELECT bonus FROM employees2 WHERE employee_id = 999返回值应为1200 - 结束处理(Teardown)里执行
DELETE FROM employees2 WHERE employee_id = 999; COMMIT;,否则下次测试会因主键冲突失败
用 utPLSQL 手动写断言更可靠
SQL Developer 的测试框架对异常路径、多分支逻辑覆盖弱,真正要验证 WHEN NO_DATA_FOUND 或 RAISE_APPLICATION_ERROR,得用 utPLSQL。
性能影响:utPLSQL 测试套件本身占内存小,但每个 ut.expect() 调用有微秒级开销;并发跑 50+ 用例时,建议用 ut.run('my_package') 批量执行,别单个 ut.run('my_package.my_test')。
- 安装后,测试包必须以
UT_开头,过程名以test_开头,例如UT_AWARD_BONUS包里的test_null_sales_amt - 捕获异常必须用
ut.expect(...).to_be_null或ut.expect(sqlcode).to_equal(-20001),直接EXCEPTION WHEN OTHERS THEN ...不算断言 - 游标输出不能直接比对,得先
OPEN cur FOR ...,再用ut.expect(cur).to_have_count(3) - 避免在测试里写
DBMS_OUTPUT.PUT_LINE—— utPLSQL 不捕获它,且干扰结果解析
参数类型与绑定容易踩的坑
PL/SQL 过程参数类型和调用时的实际值类型不一致,是单元测试失败最隐蔽的原因。Oracle 不自动隐式转换 CHAR 和 VARCHAR2,也不兼容 NUMBER 和 INTEGER 在某些上下文中。
- 输入参数传字符串时,务必用
'123'而非123—— 后者是 NUMBER,可能触发隐式转换导致索引失效或比较失败 - 输出参数声明必须严格匹配过程定义,例如过程定义
p_result OUT SYS_REFCURSOR,测试里就得用cur SYS_REFCURSOR接收,不能用cur VARCHAR2 -
IN OUT参数在测试中需先赋初值,哪怕只是NULL,否则 Oracle 报ORA-06502 - 日期参数别依赖默认格式,统一用
TO_DATE('2026-07-28', 'YYYY-MM-DD'),避免会话NLS_DATE_FORMAT差异
为什么本地测试通过,上线就失败
根本原因不是代码问题,而是测试环境和生产环境的对象权限、数据状态、NLS 设置三者之一不一致。尤其注意 HR 用户在测试库被解锁,但在生产库可能被锁或无权访问 EMPLOYEES2 表。
- 所有测试脚本开头加
SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL;,确认当前 schema 是预期的 - 测试前执行
SELECT privilege FROM dba_tab_privs WHERE grantee = USER AND table_name = 'EMPLOYEES2';,缺权限就补GRANT SELECT, INSERT, DELETE ON employees2 TO your_test_user; - 不要在测试里依赖真实业务数据,哪怕只查一条记录也得用
WHERE rownum = 1加防护,防止数据变更导致断言失效 - utPLSQL 的
beforeall和afterall里禁止写 DDL(如CREATE TABLE),DDL 会隐式提交,破坏事务隔离
真正难的不是写断言,而是让测试能稳定复现问题——每次运行都面对同一份干净数据、同一套权限、同一个字符集。这点漏掉,测试就变成运气游戏。











