如何(单元)测试数据密集型 PL/SQL 应用程序
我们的团队愿意对在扩展现有庞大 Oracle 系统的正在运行的项目下编写的新代码进行单元测试。
该系统仅用 PL/SQL 编写,由数千个表、数百个存储过程包组成,主要是从表中获取数据和/或插入/更新其他数据。
我们的扩展也不例外。大多数函数从许多相互绑定的表上的相当复杂的 SELECT 语句返回数据(在返回它们之前添加一些逻辑),或者从一个复杂的数据结构转换为另一个复杂的数据结构(以另一种方式复杂化)。
对此类代码进行单元测试的最佳方法是什么?
现有代码库没有单元测试。更糟糕的是,只有包、触发器和视图是受源代码控制的,表结构(包括“alter table”内容和必要的数据转换是通过版本控制以外的渠道部署的)。在我们的项目范围内没有办法改变这一点。
维护测试数据集似乎是不可能的,因为每周都有新代码部署到生产环境,通常不会事先通知,经常更改数据结构(此处添加一列,在那里删除一列)。
我很高兴有任何建议或参考来帮助我们。一些团队成员往往会因为弄清楚如何开始而感到疲倦,因为我们的单元测试经验并不涵盖 PL/SQL 数据密集型遗留系统(仅限于那些“从书本上”的新建 Java 项目)。
Our team is willing to unit-test a new code written under a running project extending an existing huge Oracle system.
The system is written solely in PL/SQL, consists of thousands of tables, hundreds of stored procedures packages, mostly getting data from tables and/or inserting/updating other data.
Our extension is not an exception. Most functions return data from a quite complex SELECT statementa over many mutually bound tables (with a little added logic before returning them) or make transformation from one complicated data structure to another (complicated in another way).
What is the best approach to unit-test such code?
There are no unit tests for existing code base. To make things worse, only packages, triggers and views are source-controlled, table structures (including "alter table" stuff and necessary data transformations are deployed via channel other than version control). There is no way to change this within our project's scope.
Maintaining testing data set seems to be impossible since there is new code deployed to the production environment on weekly basis, usually without prior notice, often changing data structure (add a column here, remove one there).
I'd be glad for any suggestion or reference to help us. Some team members tend to be tired by figuring out how to even start for our experience with unit-testing does not cover PL/SQL data intensive legacy systems (only those "from-the-book" greenfield Java projects).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
有几种不同的 PL/SQL 测试工具。 Steven Feuerstein 写了其中两篇,utplsql 和 Quest 代码测试器Oracle(以前称为 QUTE)。我是 utplsql 的忠实粉丝,但它不再有活跃的支持社区(这很遗憾)。它也往往非常冗长,尤其是在设置测试装置时。它确实具有纯 PL/SQL 包的基本虚拟性;源代码有点粗糙,但它是 FOSS。
QCTO 带有 GUI,这意味着 - 与其他 Quest 产品(即 TOAD)一样 - 它仅适用于 Windows。它并不完全自动化测试数据生成,但它提供了一个接口来支持它。与其他 Quest 产品一样,QCTO 已获得许可,但有免费软件副本。
Steven(透露,他是我的 Oracle 英雄之一)编写了所有 PL/SQL 测试工具的功能比较。显然,QOTC 名列前茅,但我认为这种比较是诚实的。 查看一下。
关于 utplsql 中测试装置的建议
管理单元测试的测试数据可能是一个真正的难题。不幸的是 utplsql 没有提供太多来承担这个负担。因此,
add_months()
、last_day()
、interval
、trunc(sysdate, 'MM')
、等等其他需要记住的事情:
ut_setup
本身中仅包含易失性数据。这在测试只读功能时特别有用。utAssert.EqQuery
、utAssert.EqQueryValue
、utAssert.EqTable
、utAssert.EqTabCount
和utAssert.Eq_RefC_Query
在推断易失性数据的值时都是非常有用的功能。ut_teardown
过程,并在ut_setup
开始时清除测试数据。处理遗留代码
对 Gary 帖子的评论让我想起了另一件您可能会觉得有用的事情。 Steven F 编写了 ulplsql 作为 JUnit 的 PL/SQL 实现,JUnit 是 Test First 运动的 Java 先锋。然而,TDD 技术也可以应用于大量遗留代码(在这种情况下,遗留代码是没有任何单元测试的任何程序集)。
要记住的关键是您不必立即对所有内容进行单元测试。逐步开始。为新东西构建单元测试,测试优先。在应用更改之前,为要更改的部分构建单元测试,这样您就知道它们在更改后仍然有效。
这个领域有很多想法,但(不可避免的是,可耻的是)它主要来自 OO 程序员。迈克尔·费瑟斯 (Michael Feathers) 是主角。阅读他的文章有效使用旧代码。如果您觉得有帮助,他随后写了一本同名的书。
There are several different test tools for PL/SQL out there. Steven Feuerstein has written two of them, utplsql and Quest Code Tester for Oracle (formerly QUTE). I am a big fan of utplsql, but it no longer has an active support community (which is a shame). It also tends to be quite verbose, especially when it comes to setting up test fixtures. It does have the cardinal virtual of being pure PL/SQL packages; the source code is a bit gnarly but it is FOSS.
QCTO comes with a GUI, which means - like other Quest products i.e. TOAD - it is Windows only. It doesn't exactly automate test data generation, but it provides an interface to support it. Also like other Quest products, QCTO is licensed although there is a freeware copy.
Steven (disclosure, he he is one of my Oracle heroes) has written a feature comparison of all the PL/SQL testing tools. Obviously, QOTC comes out tops, but I think the comparison is honest. Check it out.
Advice on test fixtures in utplsql
Managing test data for unit testing can be a real pain in the neck. Unfortunately utplsql doesn't offer much to shoulder the burden. So
add_months()
,last_day()
,interval
,trunc(sysdate, 'MM')
, etc.Other things to bear in mind:
ut_setup
itself. This is especially helpful when testing read-only functionality.utAssert.EqQuery
,utAssert.EqQueryValue
,utAssert.EqTable
,utAssert.EqTabCount
andutAssert.Eq_RefC_Query
are all very useful features when it comes to inferring the values of volatile data.ut_teardown
procedure and clearing down the test data at the start ofut_setup
.Dealing with legacy code
Commenting on Gary's post reminded me of one other thing you may find useful. Steven F wrote ulplsql as a PL/SQL implementation of JUnit, the Java vanguard of the Test First movement. However, the techniques of TDD can be also applied to large amounts of legacy code (in this context, legacy code is any set of programs without any unit tests).
The key thing to bear in mind is that you don't have to get everything under unit test immediately. Start incrementally. Build unit tests for new stuff, Test First. Build unit tests for the bits you're going to change before you apply the change, so you know they still work after you have made the change.
There is a lot of thought in this area, but (inevitably if shamefully) it mainly comes from the OO programmers. Michael Feathers is the main chap. Read his article Working Effectively With Legacy Code. If you find it helpful he subsequently wrote a book of the same name.
以下面的场景为例
非常简单的功能,但有一大堆可能出错的东西。数据类型转换、索引、统计数据都可能影响查询路径、性能,在某些情况下还会影响错误。还有很多松散耦合,例如会话设置(例如语言首选项)。如果有人向 table_1 添加了“LOCAL_CLIENT_ID”列,则该函数的整个逻辑就会发生变化。
我个人觉得TDD不太适合这个环境。由知识渊博的人进行代码审查将更有可能发现问题。
如果你有钱,那么看看Oracle的RAT(真实应用程序测试)进行回归测试。
Take the following scenario
Very simple function but there is a whole mess of stuff that can go wrong. Datatype conversions, indexing, stats could all impact query paths, performance and, in some cases, errors. There's also a lot of loose coupling such as session settings (eg linguistic preferences). If someone came along and added a column "LOCAL_CLIENT_ID" to table_1, the whole logic of the function changes.
I personally don't feel that TDD is suitable for this environment. Code reviews by knowledgable individuals will have a greater chance of catching problems.
If you've got money, then look at Oracle's RAT (real application testing) for regression testing.
我使用 DbFit 对 PL/SQL 代码进行单元测试。尝试一下。
I've used DbFit to unit-test PL/SQL code. Give it a try.
utPLSQL 可能会有所帮助,但听起来您需要一种更好的方法来维护测试数据。您可能还想查看 Swingbench 。
utPLSQL might help, but it sounds like you need a better way of maintaining test data. You might want to also look at Swingbench for that.