首页 > 最佳实践:使用NodeJS进行web开发,如何优雅地进行数据层的单元测试?

最佳实践:使用NodeJS进行web开发,如何优雅地进行数据层的单元测试?

仔细想了下,觉得我问的这个问题维度可大可小,我就列一下我的一些困扰吧,求给建议或者分享经验。

如何确定测试的维度?

以一个常见的web应用为例,我们一般会有数据层(完全对数据库的操作封装),面向客户端的业务接口,可能还会有面向第三方应用的API。那么如此一般你们会对那些维度进行测试呢?比如:

纠结主要在于虽然是不同层的测试,但是其实有非常多得荣誉在里面。比如数据层的一个createUser 方法的测试,对于API的HTTP层,无非可能直接就是把用户输入传到这个方法里面,然后返回这个方法的结果给客户端。

测试的具体编写你们一般怎么搞?

目前来说这些测试我都是手写,不知道大家是否有更加自动化的方式做这些测试。手写的话,我个人感觉问题有:

jsdescribe( 'common', function(){
    it( '添加用户', function( done ){
        done();
    });

    it( '获取用户列表', function( done ){
        done();
    });

    it( '获取某个用户', function( done ){
        done();
    });

    it( '更新用户', function( done ){
        done();
    });

    it( '删除用户', function( done ){
        done();
    });
});

感觉应该是比较常见的case,那么除了第一个“添加用户”外,可以看到,其他得所有case都需要“某个用户已经被添加”为前提。那么一般大家是怎么操作呢?我想到的思路有两种:


欢迎发散分享经验!!!!


按照我的经验:

所谓「业务流程」就是指类似「一个普通用户注册帐号、登录、修改密码、发帖、回复」或者「一个管理员账户登录管理员面板、发帖、回复、删除别人的发帖」的流程。这样的好处有很多,比如前面第一个流程的每个测试之间都共享同一个「普通用户」,第二个流程都共享一个「管理员用户」。

在一个流程内部共享数据可控性比较强,因为一个流程一般不会太长,而且内部的联系是比较大的。如果针对每个接口做测试的话,要么为每个测试单独准备数据(很繁琐),要么在所有测试之间共享数据(会出现很多全局变量,会很大程度上增加复杂度,测试之间互相还可能出现干扰)。

应该保证每一个测试文件里的测试是独立的,用 before 来定义这个文件所依赖的数据(比如这个文件的所有测试都需要先有一个用户),你可以在其他文件定义一个 createTestAccount 的函数,接受一些选项,然后来生成符合要求的测试数据。这样的好处就是你可以单独运行某个测试,如果运行整个测试比较耗时的话,这样可以解决很多时间,而且你也不必担心测试之间会互相干扰。而且比如 mocha 这样的库,它是不担保不同测试文件之间的运行顺序的(虽然实际会按字母顺序运行),如果不同的测试文件之间有依赖会很麻烦。

至于究竟是测 API 接口,还是测 Model, 这个就比较见仁见智了,不过「尽量把业务逻辑写到 Model」里这点是不会变的。

如果是测 API 的话,那么测试可以直接调用 Model 里的方法来准备数据和验证测试结果(比起用 API 来准备数据和验证结果,可是要方便多了);如果是测 Model 的话,因为大部分逻辑在 Model 里,所以 Model 测完就可以基本保证没有大问题了,因为 Controller 里的逻辑不多。

最后,请一定不要用「代码生成器」来生成测试代码。能够用脚本生成,说明这些测试之间是有内在的逻辑的,你完全可以通过好的设计来避免出现重复的代码,毕竟 mocha 的测试也都是 JavaScript 代码,有什么不能实现的呢?当然,测试的抽象程度不能太高了,要稍微直白一点,否则就会在「调试测试」上花太多时间,这之间需要自行做个权衡。

关于「代码生成器」请参考 程序员修炼之道:从小工到专家 一书中的「邪恶的向导」一节,这本书中亦介绍了大量编写自动测试的技巧。


我是这样做的 API测试 这个没办法 必须得做
如果你的ORM活着类似的数据引擎 是自己开发的 保证这个没问题就好了
复杂的数据操作 做一些单元测试 如果只是很简单的功能 就没必要了
当然TDD的话除外 对于创业团队 测试很难特别全面的 掌握好一个度就好了~


我的理解是:啥不变测试啥
举个例子你测试api,application public interface (short for api),这个就是不变的,因为你public了,别人都在用,你如果接口改来改去,别人针对你的api调用的,能不报错吗?
单元测试其实测试也是这个[object or element or entry] interface,不会有人测试private method or protected method吧
针对业务逻辑的测试也是一样,为啥,通常情况下,product没有release的开发阶段,业务逻辑应该是稳定,否则你怎么做,东西还没有做完,需求已经变了

实践:找出业务逻辑来测试,如果你的业务逻辑写在model里面那就测试model,写在service里,你就测试service,
通常一个api应该是对应着一个业务逻辑的,你测试了业务逻辑,自然就不用测试api了比如
user->getuser() 这个method会对应着一个http://domain.com/getuser.xxxx的api
这也是RESTful的由来我的理解,ror里面的一个method 会自动映射成一个webservice or api,让人调用

最后在强调一遍:不要那么教条,所有的测试应该基于这个原则【啥不变测试啥】,如果东西一直在变,你怎么测

【热门文章】
【热门文章】