如何实现测试隔离测试Oracle PL/SQL?

Posted

技术标签:

【中文标题】如何实现测试隔离测试Oracle PL/SQL?【英文标题】:How to achieve test isolation testing Oracle PL/SQL? 【发布时间】:2011-09-12 19:35:13 【问题描述】:

在 Java 项目中,JUnit 测试执行设置、测试和拆卸。即使在使用内存数据库模拟真实数据库时,您通常也会回滚事务或从内存中删除数据库并在每次测试之间重新创建它。这为您提供了测试隔离,因为一个测试不会在可能影响下一个测试的环境中留下工件。每个测试都以一个已知状态开始,并且不能渗透到另一个测试中。

现在我有一个创建 1100 个表和 400K 代码的 Oracle db 构建 - 很多 pl/sql 包。我不仅想测试数据库安装(完全 - 从头开始​​创建,部分 - 从以前的数据库升级等)并确保所有表和其他对象在安装后处于我期望的状态,但也在 pl/sql 上运行测试(我不确定我将如何准确地执行前者 - 建议?)。

我希望这一切都在 Jenkins 中为 CI 运行,以便通过回归测试捕获开发错误。

首先,我必须使用企业版而不是 XE,因为 XE 不支持 java SP 并且依赖于 Oracle Web Flow。即使我消除了这些依赖项,构建通常也需要 1.5 小时才能加载(完整构建)。

那么您如何在这种环境中实现测试隔离?为每个测试使用事务并将它们回滚?好的,那些有提交的 pl/sql 过程呢?

我考虑过备份和恢复以在每次测试后重置数据库,或者在每次测试之间重新创建整个数据库(太激烈了)。两者都不实用,因为安装它需要一个多小时。对每个测试都这样做是矫枉过正和疯狂的。

有没有办法在数据库模式的沙子上画一条线,然后及时回滚到那个时间点?有点像一个大的“撤消”功能。除了 expdp/impdp 或 rman 之外的东西。也许整个方法都关闭了。建议?其他人是怎么做到的?

对于 CI 或小型生产升级窗口,整个测试套件必须在合理的时间内运行(最好是 30 分钟)。

是否有产品可以帮助实现这种“撤消”功能?

【问题讨论】:

您可以捕捉 db 的克隆(比 exp/imp 或 rman 快得多),然后在克隆上运行测试。 (询问您的系统管理员) 【参考方案1】:

Kevin McCormack 在 The Server Labs 博客上发表了一篇关于使用 Maven 和 Hudson 对 PL/SQL 进行持续集成测试的文章。 Check it out。测试组件的关键成分是Steven Feuerstein's utPlsql 框架,它是 JUnit 概念在 PL/SQL 中的实现。

需要重置我们的测试装置是 PL/SQL 测试的大问题之一。有帮助的一件事是遵守良好实践并避免在存储过程中提交:事务控制应仅限于调用堆栈的最外层部分。对于那些简单地必须发出提交的程序(可能是因为它们执行 DDL 而隐含地),总是有一个测试夹具发出 DELETE 语句。处理关系完整性使那些代码变得非常棘手。

另一种方法是使用数据泵。您似乎放弃了 impdp,但 Oracle 也为它提供了 PL/SQL API,DBMS_DATAPUMP。我在这里建议它,因为它提供了在运行导入之前丢弃任何现有数据的能力。所以我们可以有一个导出的数据集作为我们的测试夹具;执行设置是运行数据泵作业的问题。您无需在 TearDown 中执行任何操作,因为整理工作发生在 SetUp 开始时。

【讨论】:

【参考方案2】:

在 Oracle 中,您可以使用闪回技术将服务恢复到某个时间点。

http://download.oracle.com/docs/cd/B28359_01/backup.111/b28270/rcmflash.htm

【讨论】:

闪回表是一项需要企业版许可证的功能:download.oracle.com/docs/cd/B28359_01/license.111/b28287/… 所以它不是一个普遍适用的解决方案。此外,数据库和/或表必须配置为支持闪回。【参考方案3】:

对于 1100 个表和 400K 的代码来说,1.5 小时似乎很长。我显然不知道你的环境细节,但根据我的经验,我敢打赌你可以把它缩短到 5 到 10 分钟。以下是我在 Oracle 中看到的两个主要安装脚本问题:

1.操作被分解成小块

您的步骤越多,开销就越大。例如,您想尽可能地整合这样的代码:

替换:

create table x(a number, b number, c number);
alter table x modify a not null;
alter table x modify b not null;
alter table x modify c not null;

与:

create table x(a number not null, b number not null, c number not null);

替换:

insert into x values (1,2,3);
insert into x values (4,5,6);
insert into x values (7,8,9);

与:

insert into x
select 1,2,3 from dual union all
select 4,5,6 from dual union all
select 7,8,9 from dual;

如果您在不同位置运行脚本和数据库,则尤其如此。当您将其乘以 10,000 时,这个微小的网络延迟开始变得重要。我所知道的每个 Oracle SQL 工具都会一次发送一个命令。

2。开发者必须共享一个数据库

这更像是一个长期的流程解决方案,而不是技术修复,但您必须在某个时候开始。大多数使用 Oracle 的地方只将它安装在几台服务器上。然后它就变成了必须小心管理的稀缺资源。人们为之争吵,角色不明确,事情没有得到解决。

如果这是您的环境,请立即停止疯狂并在每台笔记本电脑上安装 Oracle。花几百美元,给每个人提供个人版(与企业版具有相同的功能)。为每个人提供他们需要的工具,持续改进最终会解决您的问题。


此外,对于“撤消”模式,您可能需要查看可传输表空间。我从未使用过它,但据说它是安装系统的一种更快的方法——只需复制和粘贴文件而不是导入。同样,也许某种类型的虚拟化可以提供帮助 - 创建操作系统和数据库的快照。

【讨论】:

【参考方案4】:

虽然 Oracle 闪回是企业版功能,但它所基于的技术可用于所有版本,即 Oracle Log Miner:

http://docs.oracle.com/cd/B28359_01/server.111/b28319/logminer.htm#i1016535

我很想知道是否有人使用它来为功能测试提供测试隔离,即查询 v$LOGMNR_CONTENTS 以从对应于测试开始的时间点获取 UNDO 语句列表。

数据库需要处于归档模式,并且在 junit 测试用例中需要一个带有注释的方法

@Startup 

将调用 DBMS_LOGMNR.START_LOGMNR。测试将运行,然后在带有注释的方法中运行

@Teardown

将查询 v$LOGMNR_CONTENTS 以查找 UNDO 语句列表。然后这些将通过 JDBC 执行。事实上,UNDO 语句的查询和执行可以被提取到一个 PLSQL 存储过程中。必须考虑语句执行的顺序。

我认为这样做的好处是允许事务提交,这就是大量错误可能蔓延的地方,即参照完整性、主键违规等。

【讨论】:

以上是关于如何实现测试隔离测试Oracle PL/SQL?的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE PL/SQL:在 Oracle SQL Developer 中测试 SELECT FOR UPDATE

PL/SQL oracle,使用日期和时间的测试窗口

PL/SQl,oracle 9i,使用sql删除重复行

PL/SQL中测试存储过程,如何立即输出DBMS_OUTPUT的语句。

oracle学习

oracle中如何创建一个job