依赖于数据的工程如何进行单元测试?
做一个项目势必要进行单元测试以保证程序的健壮性,以便保证版本迭代时功能正常。但是如果一个程序(如CMS等)本身就是依赖于数据库的,应该如何在保证不会破坏数据库的情况下进行单元测试呢?
举例:
访问?id=1的页面,先查询
sql
SELECT * FROM `data` WHERE `ID` = 1
,然后将其赋值给
$data->ID
、
$data->Title
这些属性;
要保证这些属性的值正常
。
然后,根据一些信息算出
$data->Hash
,如
$data->Hash = md5($data->ID)
,
这些计算的值也要正常
。
接着,删除
id=1
的文章,要
sql
DELETE FROM `data` WHERE `ID` = 1
,
必须保证ID所在行被删除
。
再其次,后台发布一篇文章,必须使得数据库内多出
ID=2
,内容为设定值的文章。但是HTML代码内容不一定要相同,可以允许诸如多余的空格、换行。
还需要模拟XML-RPC协议发表一篇文章。
像以上的内容,应该如何进行单元测试呢?
Answers
用单独的数据库运行测试,每次测试开始前都清空数据库,并重新生成测试数据。
另一种做法是每次生成测试数据的时候记录下来生成的数据的 ID, 然后在完成测试后删除本次生成的数据,而不是每次都清空数据库。这种方案比较适合既需要自动测试,又需要手动测试的情况,自动测试不会导致手动测试时添加的数据被删除。
测试最好别依赖于具体的值(比如你的例子的 ID=1),最好用单独的函数来创建每一条测试数据(比如
generateAccount
和
generateArticle
),这些函数返回创建出来的数据的 ID, 否则如果硬编码 ID 的话,在添加或移除测试的时候会很麻烦。
首先,请先想清楚你要作的是
单元
测试还是功能测试。
如果你的目的是验证这两个页面是否正常工作,你想做的是功能测试。这种情况下,可以先配置好测试数据,用selenium之类工具进行测试。
如果要作单元测试,那么你要测的是哪个
单元
?
也许从代码来看一个显示ID和title的页面已经非常简单了,但它并非一个单元。
事实上它处理了http请求,绑定了URL参数,用参数查询了数据库,从数据库返回结果中读取了需要的数据,做了
业务逻辑需要的处理
,根据处理结果绑定了一些数据到页面模版中,把模版渲染成为html页面,发送页面给客户端,如果页面上有js之类的脚本的话,还需要在客户端浏览器中执行这些脚本。之后用户才真正看到了页面。
上面任何一步出错,都会导致这个页面工作不正常。
很少有程序单元能不依赖于环境独立完成功能,它能做的是根据环境提供的输入,给出正确的输出。相应的,单元测试无法保证整个功能正常工作,只能验证这个单元接受特定的输入后,给出的是预期的输出。
所幸的是,大部分的依赖都是成熟的第三方代码。一般来说,只要给出了正确的输入数据,它们就会产生正确的输出(行为)。因而可以假设我们测试的关注点,在于确保我们自己写的代码,在从依赖环境中获得了正确输入后,向其它依赖正确的输出。
比如说,当你测试时,一般不会怀疑输入了?id=1后你的代码却从参数中读出id=0,因为那是你的代码信赖的第三方,你只要确认给它的输入是正确的。同样的,如果你确认了delete的SQL语句是正确的,一般来说也没有必要去怀疑数据库是否正确的执行这条语句。
从你的问题来看,你大部分的问题关注的是功能测试而非单元,所以可能单元测试并不是你真正需要的。如果要作的话,可能主要要测md5相关的那一部分。
另一个关于单元测试但是超出测试的问题,从你的描述来看似乎你的程序里并没有单元,这可能也会对单元测试造成一些困难。