Database 什么';对数据库驱动的应用程序进行单元测试的最佳策略是什么?
我处理的很多web应用程序都是由后端复杂程度不同的数据库驱动的。通常,有一个独立于业务和表示逻辑的层。这使得业务逻辑的单元测试相当简单;事情可以在离散的模块中实现,测试所需的任何数据都可以通过对象模拟来伪造 但是测试ORM和数据库本身总是充满问题和妥协 这些年来,我尝试了一些策略,但没有一个能让我完全满意Database 什么';对数据库驱动的应用程序进行单元测试的最佳策略是什么?,database,unit-testing,orm,mocking,Database,Unit Testing,Orm,Mocking,我处理的很多web应用程序都是由后端复杂程度不同的数据库驱动的。通常,有一个独立于业务和表示逻辑的层。这使得业务逻辑的单元测试相当简单;事情可以在离散的模块中实现,测试所需的任何数据都可以通过对象模拟来伪造 但是测试ORM和数据库本身总是充满问题和妥协 这些年来,我尝试了一些策略,但没有一个能让我完全满意 用已知数据加载测试数据库。对ORM运行测试并确认返回了正确的数据。这里的缺点是测试数据库必须跟上应用程序数据库中的任何模式更改,并且可能会失去同步。它还依赖于人工数据,并且可能不会暴露由于愚
- 用已知数据加载测试数据库。对ORM运行测试并确认返回了正确的数据。这里的缺点是测试数据库必须跟上应用程序数据库中的任何模式更改,并且可能会失去同步。它还依赖于人工数据,并且可能不会暴露由于愚蠢的用户输入而出现的错误。最后,如果测试数据库很小,它将不会显示诸如缺少索引之类的低效率。(好的,最后一个问题并不是单元测试应该用来做的事情,但它并没有坏处。)
- 加载生产数据库的副本并根据该副本进行测试。这里的问题是,您可能不知道在任何给定的时间生产数据库中有什么内容;如果数据随时间变化,您的测试可能需要重写
- 使用模拟数据库服务器,仅检查ORM是否发送正确的查询以响应给定的方法调用
您使用了哪些策略来测试数据库驱动的应用程序(如果有的话)?什么对您最有效?实际上,我使用了您的第一种方法,取得了一定的成功,但我认为这是一种稍微不同的方法,可以解决您的一些问题:
这是我上一份工作中使用的方法。这是几个问题造成的巨大痛苦:
我们在我目前的工作中也这样做。在每次提交之后,我们对已注入模拟db访问器的应用程序代码执行单元测试。然后,我们每天执行三次上述完整的数据库构建。我绝对推荐这两种方法。我问这个问题已经很久了,但我认为没有解决这个问题的灵丹妙药 我目前所做的是模拟DAO对象,并在内存中保留一个良好的对象集合表示,这些对象表示可能存在于数据库中的有趣的数据案例 我看到这种方法的主要问题是,您只涉及与DAO层交互的代码,而从不测试DAO本身,根据我的经验,我发现在该层上也会发生很多错误。我还保留了一些针对数据库运行的单元测试(为了在本地使用TDD或快速测试),但这些测试从未在我的持续集成服务器上运行,因为我们没有为此目的保留数据库,我认为在CI服务器上运行的测试应该是自包含的 我发现另一种方法非常有趣,但并不总是值得的,因为它有点费时,就是在一个嵌入式数据库上创建用于生产的相同模式,该数据库只在单元测试中运行 尽管毫无疑问,这种方法可以提高您的覆盖率,但也有一些缺点,因为您必须尽可能接近ANSI SQL,才能使其与当前的DBMS和嵌入式替代品一起工作
无论您认为什么与您的代码更相关,都有一些项目可以让它变得更简单,例如。出于以下原因,我总是对内存中的DB(HSQLDB或Derby)运行测试:
- 它会让您思考在测试数据库中保存哪些数据以及为什么要保存这些数据。将生产数据库拖到测试系统中就意味着“我不知道我在做什么,也不知道为什么,如果出现故障,那不是我!!”;)李>
- 它可以确保在一个新的地方(例如,当我们需要从生产中复制一个bug时)轻松地重新创建数据库
- 它极大地提高了DDL文件的质量
@Test
public void savedCommentCanBeRead() {
// Builder is needed to declaratively specify the entity with all attributes relevant
// for this specific test
// Missing attributes are generated with reasonable values
// factory's responsibility is to create entity (and all entities required by it
// in our example Author) in the DB
Post post = factory.create(PostBuilder.post());
Comment comment = CommentBuilder.comment().forPost(post).build();
sut.save(comment);
Comment savedComment = sut.get(comment.getId());
// this checks fields that are directly stored
assertThat(saveComment, fieldwiseEqualTo(comment));
// if there are some fields that are generated during save check them separately
assertThat(saveComment.getGeneratedField(), equalTo(expectedValue));
}