node.js - 最佳实践:使用NodeJS进行web开发,如何优雅地进行数据层的单元测试?
PHP中文网
PHP中文网 2017-04-17 11:33:36
0
3
374

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

如何确定测试的维度?

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

  • 数据层做单元测试?
  • 针对API做http接口测试?

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

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

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

  • 机械重复劳动:比如你的业务中有userappproject这些事例,那么这三者的所谓"增删改查"的用例基本上千篇一律,可能你写完user,后面的appproject基本上就是复制过来然后改改名字了。
  • 模拟数据构造的繁琐
  • 缺少最佳实践的指导,比如下面这样的情况:
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都需要“某个用户已经被添加”为前提。那么一般大家是怎么操作呢?我想到的思路有两种:

  • 方案一:在每个case里面自己独立 添加一个新用户,结束的时候再删除掉这个用户(可以使用mocha的beforeEachafterEach
  • 方案二:创建一个全局的新用户变量,在第一个case跑完后,复制到这个变量中,后续的case就直接使用这个变量即可

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

PHP中文网
PHP中文网

认证0级讲师

全部回覆(3)
巴扎黑

按照我的經驗:

  • 測試要以「業務流程」為單位,而不是以「介面」為單位
  • 不同的測試之間不要共享數據,盡可能不要使用全域變數
  • 商業邏輯盡量往 Model 寫(或單獨抽像出一個 Service 層),不要寫在 Controller
  • 如果發現重複的測驗比較多的話,可以先不寫測驗(或只對其中一個地方寫測驗),等到發現某個功能有問題,再針對問題寫測驗

所謂「業務流程」就是指類似「一個一般使用者註冊帳號、登入、修改密碼、發文、回覆」或「一個管理者帳號登入管理員面板、發文、回覆、刪除別人的發文」的流程。這樣的好處有很多,例如前面第一個流程的每個測試之間都共用同一個「普通使用者」,第二個流程都共用一個「管理員使用者」。

在一個流程內部共享資料可控性比較強,因為一個流程一般不會太長,而且內部的聯繫是比較大的。如果針對每個介面做測試的話,要么為每個測試單獨準備數據(很繁瑣),要么在所有測試之間共享數據(會出現很多全局變量,會很大程度上增加複雜度,測試之間互相也可能出現幹擾)。

應該確保每一個測試文件裡的測試是獨立的,用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,讓人呼叫

最後在強調一遍:不要那麼教條,所有的測驗應該基於這個原則【啥不變測試啥】,如果東西一直在變,你怎麼測

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板