单位的最佳策略是什么?
我与许多由后端数据库变得复杂的Web应用程序一起工作。 通常,有一个独立于业务逻辑和表示逻辑的ORM层。 这使得单元测试业务逻辑非常简单; 事情可以在离散模块中实现,并且测试所需的任何数据都可以通过对象模仿来伪造。
但是测试ORM和数据库本身一直充满着问题和妥协。
多年来,我尝试了一些策略,其中没有一个能完全令我满意。
用已知数据加载测试数据库。 针对ORM运行测试并确认正确的数据返回。 这里的缺点是,测试数据库必须跟上应用程序数据库中的任何模式更改,并且可能不同步。 它也依赖于人造数据,并且可能不会公开由于愚蠢的用户输入而发生的错误。 最后,如果测试数据库很小,它不会像缺少索引一样显示效率低下。 (好吧,最后一个不是真的应该使用单元测试,但它并没有受到伤害。)
加载生产数据库的副本并进行测试。 这里的问题在于,您可能不知道在任何给定时间内生产数据库中的内容; 如果数据随时间变化,您的测试可能需要重写。
有些人指出,这两种策略都依赖于特定的数据,单元测试应该只测试功能。 为此,我已经看到了建议:
你有什么策略用于测试数据库驱动的应用程序,如果有的话? 什么最适合你?
实际上,我已经使用了第一种方法,取得了相当大的成功,但以一种稍微不同的方式解决了一些问题:
保留整个模式和脚本以在源代码控制中创建它,以便任何人都可以在签出后创建当前数据库模式。 另外,将样本数据保存在由部分构建过程加载的数据文件中。 当您发现导致错误的数据时,请将其添加到您的示例数据中,以检查错误是否不会重新出现。
使用持续集成服务器来构建数据库模式,加载示例数据并运行测试。 这就是我们如何保持测试数据库同步(在每次测试运行时重新构建它)。 虽然这要求CI服务器可以访问和拥有自己的专用数据库实例,但我认为每天创建3次我们的db模式极大地帮助发现了可能直到交付之前才发现的错误(如果不晚于)。 我不能说我在每次提交之前重建模式。 有人吗? 采用这种方法,你不必(也许我们应该,但是如果有人忘记了,这不是什么大问题)。
对于我的组,用户输入是在应用程序级别(而不是db)完成的,所以这是通过标准单元测试来测试的。
加载生产数据库副本:
这是我上一份工作使用的方法。 这是几个问题的巨大痛苦原因:
嘲笑数据库服务器:
我目前的工作也是这样做的。 每次提交后,我们都会针对注入了模拟db访问器的应用程序代码执行单元测试。 然后,我们每天执行三次上面描述的完整db构建。 我绝对推荐这两种方法。
由于以下原因,我总是针对内存数据库(HSQLDB或Derby)运行测试:
一旦测试开始,大多数测试结束后,内存数据库都会加载新数据,我会调用ROLLBACK来保持稳定。 始终保持测试数据库中的数据稳定! 如果数据始终在变化,则无法进行测试。
数据从SQL,模板数据库或转储/备份中加载。 如果它们的可读格式我更喜欢转储,因为我可以将它们放入VCS中。 如果这不起作用,我使用CSV文件或XML。 如果我必须加载大量的数据......我不知道。 你永远不需要加载大量的数据:)不适用于单元测试。 性能测试是另一个问题,适用不同的规则。
我一直在问这个问题很长一段时间,但我认为这没有什么银弹。
我目前所做的是嘲笑DAO对象,并在内存中表示一组代表可以存在于数据库中的有趣数据的对象。
我用这种方法看到的主要问题是,你只覆盖了与DAO层交互的代码,但从未测试DAO本身,并且根据我的经验,我发现在该层上也发生了很多错误。 我还保留了一些针对数据库运行的单元测试(为了使用TDD或本地快速测试),但这些测试从未在我的持续集成服务器上运行,因为我们没有为此目的而保留数据库,认为在CI服务器上运行的测试应该是自包含的。
我发现另一种非常有趣的方法,但并不总是值得,因为它有点花费时间,因此需要在嵌入式数据库中创建与在单元测试中运行相同的模式。
尽管这种方法毫无疑问可以提高覆盖范围,但还是有一些缺点,因为您必须尽可能接近ANSI SQL才能使其与当前的DBMS和嵌入式替代品一起使用。
不管你认为什么与你的代码更相关,那里有一些可能使它更容易的项目,比如DbUnit。
链接地址: http://www.djcxy.com/p/37943.html