谈一下我们是怎么做数据库单元测试(Database Unit Test)的

本文介绍了在Sql Server环境下进行数据库单元测试的实践,包括背景介绍、数据准备、测试要点和一个从创建数据库到运行测试用例的完整示例。文章强调了数据隔离的重要性,提出通过在TestCleanup()中恢复数据库状态或在PretestAction中记录并回滚操作来实现数据隔离,并提到有序测试(Ordered Test)在确保测试用例执行顺序方面的作用。
摘要由CSDN通过智能技术生成

背景介绍

最近在团队在做release之前的regression,把各个feature分支merge回master之后发现DB的单元测试出现了20多个失败的test cases。之前没怎么做过DB的单元测试,正好借这个机会熟悉一下写DB单元测试的流程。

这篇博文中首先介绍一下在我们的特定项目场景中是如何搭建DB 单元测试框架的,然后举一个简单的例子,从头到尾在visual studio中创建一个简单的单元测试工程。

我们开发的产品使用的数据库为Sql Server,总共有400多张表,2000多个存储过程,每个存储过程都相当于应用代码中的一个功能函数。代码中的每个复杂的功能函数都可以通过写单元测试来在一定程度上保证代码质量,存储过程也如此。代码中的UT难点在于解耦,也就把相互牵连在一起的代码彼此分离开来,各个击破,例如A函数需要B函数提供的数据,测试A函数的时候我们只想测试A函数,不想调用B,这时候就需要我们自己提供B函数生成的数据。这叫做mock。

在做DB单元测试的时候,存储过程所使用的数据比较特殊,都是持久化在数据库表中的,2000多个存储过程增删改查400多个表,我们需要把这些表的数据为每个存储过程做隔离,如果测试用例使用的数据相互之间关联,恐怕会天下大乱,因为在一般情况下,单元测试用例的运行顺序都是随机的,如果单元测试使用的数据有关联,很有可能两次运行结果也是随机的(但是有一种方法可以固定case执行顺序,我在最后的例子中进行说明),我们这次的20多个失败的cases就有这种原因导致的,两台机器上跑出的结果不一样,有的成功,有的失败。

注:有关单元测试的定义,见另外一篇帖子,单元测试有毒

那么问题就来了,如何才能做数据的隔离呢?说一下我们的方案。


准备数据

我们创建了一个基准的数据库,做出一个备份,叫做base.bak,这个版本比较低,比如是2.8,这里面包含了一些测试的基本数据。然后我们创建了另外一个preparation的工程,用于把base.bak升级到当前release版本,例如,当前release的版本为2.18。这个工程同时也测试了升级的流程。升级成功之后,把这个数据库在本地做一个备份release_2_18.bak。好了,数据都准备好了。



测试需要注意的要点

四个函数

对于微软的这个DB UT测试框架,有四个函数需要搞清楚,因为这可能影响你的测试结果:

[ClassInitialize]public static void ClassInitialize(TestContext testContext){
    ...
}
[ClassCleanup]public static void ClassCleanup(){
   ...
}
[TestInitialize()]public void TestInitialize(){
   ...
}
[TestCleanup()]public void TestCleanup(){            
   ...
}
  • 顾名思义,ClassInitialize() 是在每个类初始化的时候被调用的

  • ClassCleanup() 是在类结束的时候,也就是一个类所有的case跑完的时候被调用的

  • TestInitialize() 是在每个case跑之前被调用的。

  • TestCleanup() 是在每个case调用之后被调用的。

对么?粗体的这句话不对,其余是对的。

测试用例的运行是无序的,包含多个类的情况。

看下面测试用例的之情情况你就明白了:

AssemblyInitialize

TestClass1: ClassInitialize

TestClass1: TestInitialize

TestClass1: MyTestCase1

TestClass1: TestCleanup

TestClass2: ClassInitialize

TestClass2: TestInitialize

TestClass2: MyTestCase2

TestClass2: TestCleanup

TestClass1: ClassCleanup

TestClass2: ClassCleanup

AssemblyCleanup

ClassCleanup() 并不意味着TestClass1ClassCleanup 在这个类的最后一个case跑完之后被立即调用!事实上,它会等待所有case都被运行完之后,同TestClass2ClassCleanup 一块执行。

<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值