依赖于数据的工程如何进行单元测试?


做一个项目势必要进行单元测试以保证程序的健壮性,以便保证版本迭代时功能正常。但是如果一个程序(如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协议发表一篇文章。

像以上的内容,应该如何进行单元测试呢?

知乎同名问题: http://www.zhihu.com/question/28278690

单元测试 项目管理 php 程序设计 软件工程

放暑假的小学生 9 years, 8 months ago

使用三种数据库配置:
dev: 开发时使用的数据库配置
test: 测试用的数据库配置, 每次自动清空和load fixtures
production: 部署时生产环节的数据库配置

Draugur answered 9 years, 8 months ago

用单独的数据库运行测试,每次测试开始前都清空数据库,并重新生成测试数据。

另一种做法是每次生成测试数据的时候记录下来生成的数据的 ID, 然后在完成测试后删除本次生成的数据,而不是每次都清空数据库。这种方案比较适合既需要自动测试,又需要手动测试的情况,自动测试不会导致手动测试时添加的数据被删除。

测试最好别依赖于具体的值(比如你的例子的 ID=1),最好用单独的函数来创建每一条测试数据(比如 generateAccount generateArticle ),这些函数返回创建出来的数据的 ID, 否则如果硬编码 ID 的话,在添加或移除测试的时候会很麻烦。

Mio-L answered 9 years, 8 months ago

插件得在你的git初始化了这个目录才行。他这样的原因就是没有找到当前路径里的git文件夹,这个文件夹里有远程的地址。

裸奔小面包 answered 9 years, 8 months ago

你用isolating test、mock、fakes关键字搜索一下,就知道怎么做对外部数据/逻辑有依赖的单元测试了。

mikiya answered 9 years, 8 months ago

首先,请先想清楚你要作的是 单元 测试还是功能测试。
如果你的目的是验证这两个页面是否正常工作,你想做的是功能测试。这种情况下,可以先配置好测试数据,用selenium之类工具进行测试。
如果要作单元测试,那么你要测的是哪个 单元
也许从代码来看一个显示ID和title的页面已经非常简单了,但它并非一个单元。
事实上它处理了http请求,绑定了URL参数,用参数查询了数据库,从数据库返回结果中读取了需要的数据,做了 业务逻辑需要的处理 ,根据处理结果绑定了一些数据到页面模版中,把模版渲染成为html页面,发送页面给客户端,如果页面上有js之类的脚本的话,还需要在客户端浏览器中执行这些脚本。之后用户才真正看到了页面。
上面任何一步出错,都会导致这个页面工作不正常。
很少有程序单元能不依赖于环境独立完成功能,它能做的是根据环境提供的输入,给出正确的输出。相应的,单元测试无法保证整个功能正常工作,只能验证这个单元接受特定的输入后,给出的是预期的输出。
所幸的是,大部分的依赖都是成熟的第三方代码。一般来说,只要给出了正确的输入数据,它们就会产生正确的输出(行为)。因而可以假设我们测试的关注点,在于确保我们自己写的代码,在从依赖环境中获得了正确输入后,向其它依赖正确的输出。
比如说,当你测试时,一般不会怀疑输入了?id=1后你的代码却从参数中读出id=0,因为那是你的代码信赖的第三方,你只要确认给它的输入是正确的。同样的,如果你确认了delete的SQL语句是正确的,一般来说也没有必要去怀疑数据库是否正确的执行这条语句。
从你的问题来看,你大部分的问题关注的是功能测试而非单元,所以可能单元测试并不是你真正需要的。如果要作的话,可能主要要测md5相关的那一部分。
另一个关于单元测试但是超出测试的问题,从你的描述来看似乎你的程序里并没有单元,这可能也会对单元测试造成一些困难。

克劳德史克莱夫 answered 9 years, 8 months ago

Your Answer