背景
- 之前用java和hibernate一起操作mysql,做单元测试时候,有一个rollback的注解,所以无论你做了哪些些操作,该方法运行结束后,数据库又回复原样(当然也是测试数据库)。所以如果初始化数据库时有数据,无论你delete多少也都没关系啦。。。
- 现在公司用node+mysql,做单元测试很头疼。首先公司初始化数据库时,很多表是空的,所以要测试时就要提前插入数据,如果遇到表级级联的时候就更恼火,要在几个表里插入数据;其次不知道有没有回滚机制?反正我现在是木有,所以每delete一条数据,我就要再insert一条来保证后面有数据可操作。
问题
- node里面做单元测试时会不会像java那样有rollback呢?
- 测试间依赖问题,比如说我要测试insert功能,如果没有rollback功能,我就要在insert完毕后再delete掉。在一个it里面相当有测试了两个方法。 如果我分开写 insert的it 在 delete的it 前面,那样我就可以把前者的id用在后面上,但是这样存在的问题是严重依赖,前面失败后面必然失败。
虽然归根接地是数据库测试数据不完善的问题,但是在这样不完善的数据库上我给怎么测试呢?球知道
单元测试应该不依赖数据库吧。 mock
@wehtta 我们这单元测试都是后来补上的,就是检查下CURD。工程都上线了还在补写这个。
@i5ting 大大求指导
这个应该是通过事务实现的吧,那在每个单元测试之前开始一个事务,测试完成之后回滚应该是可以的。 不过要保证每个测试拿到的是同一个 connection 实例
@klesh 正解,但是对于mongodb似乎就不行了,因为他没有事务
@XGHeaven 楼主说得是mysql,用 innodb 引擎的话是支持事务的。
一般性来讲,单元测试如果牵涉到数据库,我觉得应该是要有一个专门测试用的数据库实例,每次测试开始之前重新创建,初始化好,然后开始跑测试。测试用例按这个先决条件去设定,就不用考虑数据库方面是否支持事务处理了。同时也能保证数据库的可控性。测试很重要的一点就是测试环境的可控性。
@klesh 我觉得这是可以的,前提是这个是针对业务比较成熟的那些东西来的,但是对于其他的创业公司来说,业务变动非常频繁,这个测试也不好做
mocha有很多hook,比如after,before,afterEach,beforeEach,你可以在这里面做清理的工作
插入测试数据应该也是单元测试或集成测试的一部分,不应该与测试程序分离,可以在测试程序一开始的时候,用程序启动一个实例,插入事先准备好的数据,测试结束后,停掉服务
我也遇到这个问题,一般我都是测试开始插入测试数据,测试结束删除掉测试数据,感觉挺不爽的,不知道有没有其他解决方案
@fengliner 可以用 Fixtures 来解决,测试本身是不会互相依赖的,依赖的只有数据,或者直接用我团队内部的工具:https://github.com/weflex/fibula.js
@fengliner 新建一个全新的测试专用的数据库,检测开始时检测数据库是否存在,存在就先删除再新建然后插入数据。结束的时候不就用管它了,有时候还可以打开看一下数据是否正确。
你这根本不叫单元测试。 单元测试是只测试被测单元内部的,对于外部环境(读写文件、数据库、通讯)不应该有依赖。 需要用类似sinon.js的模块进行依赖注入,从而模拟各种可能出现的异常。
单元测试是保证内部被测单元的逻辑,需要排除外部环境的依赖,直接对db操作造成日常环境不稳定。所以肯定要使用mock或者spy模块来解决,除非要测的是sql逻辑,这个和单元测试可不一样。
mocha的话没有rollback 只有一推hook来重新初始化测试环境 一般before初始化 end的时候清理
@pisceswin 恩,我也觉得不是单元测试,只是测一下最底层的“dao”层的CURD通不通,感觉这样做没啥意思
@christineRR 只是简单测一下CURD通不通,是不是不叫单元测试啊。看来我要补一下这块知识了
简单的CURD根本没有测试的必要,但是复杂的情况是有必要测试的,比如一个对象传进去要保存父子关系,相互关联关系,牵涉到事务的,需要保证数据一致性,或者要处理并发插入等等。 说单元测试不能牵涉到数据库什么的,我觉得太极端,如果说我就是在做一个面向数据库为主的程序呢?比方说这个程序有好几个进程需要协同工作对数据库里的数据进行处理呢?怎么保持一致性? 当然,不牵涉到数据库的部分要尽量分离出来,独立测试。在设计时要就考虑对象的可测试性,这样设计出来的程序也比较好理解。