欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

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

程序员文章站 2022-04-30 09:33:53
...
做一个项目势必要进行单元测试以保证程序的健壮性,以便保证版本迭代时功能正常。但是如果一个程序(如CMS等)本身就是依赖于数据库的,应该如何在保证不会破坏数据库的情况下进行单元测试呢?

举例:
访问?id=1的页面,先查询

sqlSELECT * FROM `data` WHERE `ID` = 1

,然后将其赋值给$data->ID$data->Title这些属性;要保证这些属性的值正常
然后,根据一些信息算出$data->Hash,如$data->Hash = md5($data->ID)这些计算的值也要正常
接着,删除id=1的文章,要

sqlDELETE FROM `data` WHERE `ID` = 1

必须保证ID所在行被删除
再其次,后台发布一篇文章,必须使得数据库内多出ID=2,内容为设定值的文章。但是HTML代码内容不一定要相同,可以允许诸如多余的空格、换行。
还需要模拟XML-RPC协议发表一篇文章。

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

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

回复内容:

做一个项目势必要进行单元测试以保证程序的健壮性,以便保证版本迭代时功能正常。但是如果一个程序(如CMS等)本身就是依赖于数据库的,应该如何在保证不会破坏数据库的情况下进行单元测试呢?

举例:
访问?id=1的页面,先查询

sqlSELECT * FROM `data` WHERE `ID` = 1

,然后将其赋值给$data->ID$data->Title这些属性;要保证这些属性的值正常
然后,根据一些信息算出$data->Hash,如$data->Hash = md5($data->ID)这些计算的值也要正常
接着,删除id=1的文章,要

sqlDELETE FROM `data` WHERE `ID` = 1

必须保证ID所在行被删除
再其次,后台发布一篇文章,必须使得数据库内多出ID=2,内容为设定值的文章。但是HTML代码内容不一定要相同,可以允许诸如多余的空格、换行。
还需要模拟XML-RPC协议发表一篇文章。

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

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

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

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

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

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

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

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

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