javascript單元測試:jasminejs 2.0的煩惱

 前言:

 

  我屬於TDD的擁護者,之前寫後端代,都喜歡把一些重要的邏輯代碼抽離處理,增加Unit Test。可是最近在接觸前端Unit Test時,讓自己忍不住想吐槽一下。也順便實現一下今年的目標(一個月至少一篇技術博客,1月2月我會補上的)。前端測試框架有很多,比較流量的是Qunit和Jasminejs,這兩個多單元測試框架的具體區別網上有很多資料,有興趣大傢可以去查一下。我是因為Jasminejs比較豐富的斷言、斷言擴展、spy、mock這些功能吸引著我。所以首先把jasminejs引入項目中。當時主要引入的是1.3版本。

 

  最近在學習2.0版本,發現引入2.0版本的jasminejs代碼,我的整個Unit Test跑不起來瞭。盡然不向下兼容?不兼容的問題讓我頓時覺得jasminejs有點小兒科的感覺。幸虧做瞭一些封裝,不然我是沒辦法升級瞭。

 

  現在網上關於jasminejs的介紹大多數是針對1.3這個版本,下面是我排查和總結的經驗,為自己做個筆記,也和大傢分享一下。有錯誤地方請大傢拍磚。

 

  本文隻針對1.3和2.0區別做說明,至於jasminejs詳細學習手冊建議大傢上官網,介紹的很詳細。

 

  jasminejs:https://jasmine.github.io/

 

  jasminejs github: https://github.com/pivotal/jasmine/

 

  區別:

 

  1、calls區別:

 

  測試代碼:

 

復制代碼

describe("對spy函數的測試", function() {

 

         var foo, bar = null;

 

 

 

         beforeEach(function() {

 

              foo = {

 

                   setBar: function(value) {

 

                       bar = value;

 

                   }

 

              };

 

 

 

              spyOn(foo, 'setBar'); //foo為spy函數

 

 

 

              foo.setBar(123);

 

              foo.setBar(456, 'another param');

 

         });

 

 

 

         it("上一次被調用的參數", function() {

 

              var most = foo.setBar.calls;

 

              expect(most).toBeDefined();

 

         });

 

     });

復制代碼

  1.3版本: 

 

  如圖,chrome跟蹤結果。

 

     

 

     calls是一個數組,返回每次調用的上下文。數組最後一個值和mostRecentCall值相等。

 

expect(foo.setBar.calls[foo.setBar.calls.length-1]).toEqual(foo.setBar.mostRecentCall);

     2.0版本:

 

  如圖,chrome跟蹤結果。

 

     

 

     calls是一個CallTracker的實例對象。這樣更規范一些,用類封裝瞭調用相關的信息。類中所有方法說明見下面。

 

  2、1.3 mostRecentCall和2.0.calls.mostRecent()區別

 

  (1)、調用方式不同

 

     前者是:被調用方法.mostRecentCall,例如:foo.setBar.mostRecentCall

 

     後者是:被調用方法.calls.mostRecent,例如:foo.setBar.calls.mostRecent()

 

  (2)、值相同

 

  mostRecentCall是一個對象,有兩個屬性:args和object,其中args是調用方法是所傳的參數,object是調用方法的所屬對象。

 

復制代碼

describe("對spy函數的測試", function() {

          var foo, bar = null;

 

          beforeEach(function() {

               foo = {

                    setBar: function(value) {

                         bar = value;

                    }

               };

 

               spyOn(foo, 'setBar'); //foo為spy函數

 

               foo.setBar(123);

               foo.setBar(456, 'another param');

          });

 

          it("上一次被調用的參數", function() {

               expect(foo.setBar.mostRecentCall.args[0]).toEqual(456);

          });

 

          it("上一次被調用的參數", function() {

               expect(foo.setBar.mostRecentCall.object === foo).toEqual(true);

          });

     });

復制代碼

   .calls.mostRecent()是函數,返回一個對象,同上。

 

  3、2.0中強大的calls對象

 

  

 

  .calls.any() 至少一次被調用,返回false/true。

 

  .calls.count()被調用次數

 

  .calls.argsFor(index)返回被index+1次調用的參數,返回值為[]

 

 .calls.argsFor(index)

  .calls.allArgs()返回所有被調用的參數,以逗號隔開,每一次調用的參數,以數組[]的形式返回

 

  .calls.all()同1.3中calls。返回每次調用的上下文context。

 

  .calls.mostRecent()同1.3的mostRecentCall,返回最近一次調用的上下文信息。等同於.calls.all()[.calls.call().length – 1]

 

  .calls.first等同於.calls.all()[0]

 

  .calls.reset()重置spy的所有信息,此時.call.any()返回false。

 

   4、異步啊異步

 

  1.3為瞭實現異步測試,jasminejs使用瞭一種很初級的方法,循環等待。

 

復制代碼

describe("Asynchronous specs", function() {

        var value, flag;

 

        it("should support async execution of test preparation and expectations", function() {

 

            runs(function() {

                flag = true;

                value = 0;

 

                setTimeout(function() {

                    flag = true;

                }, 500);

            });

 

            waitsFor(function() {

                value++;

                return flag;

            }, "The Value should be incremented", 450);

 

            runs(function() {

                expect(value).toBeGreaterThan(0);

            });

        });

    });

復制代碼

  這裡的異步有以下幾個問題:

 

  1、寫法太過復雜,需要自己封裝;

 

  2、實現有點初級。

 

  waitsFor有三個參數:

 

  第1個參數:校驗異步是否完成函數,返回值為bool,返回true,停止循環等待;

 

  第2個參數:錯誤提示,如果操作第3個參數指定的毫秒數,第1個參數還是返回false,斷言失敗。提示信息如下:

 

  

 

  第3個參數:循環等待的時間,單位:毫秒。

 

  異步實現,大多是ajax請求,這個請求受網絡、服務器環境等諸多因素影響,所以很難估算需要多長時間。

 

  2.0對這個async test做瞭很大的優化,也更合理瞭。

 

復制代碼

describe("Asynchronous specs", function() {

        var value;

 

        beforeEach(function(done) {

            setTimeout(function() {

                value = 0;

                done();

            }, 1);

        });

 

        it("should support async execution of test preparation and expectations", function(done) {

            value++;

            expect(value).toBeGreaterThan(0);

            done();

        });

    });

復制代碼

  采用瞭一種pub/sub訂閱模式處理,ajax請求成功,通知it執行。

 

  5、僅僅寫法不同

 

  下面主要是功能一樣,但是寫法發生變化。

 

1.3和2.0版本對照表

1.3 2.0 說明

andCallThrough .and.callThrough 函數監視器,但函數真的執行

andReturn .and.returnValue 函數監視器,函數不真的執行。指定監視的函數的返回值

andCallFake .and.callFake 替代被監視的函數,原函數不執行

calls     .calls.all() 返回每次調用的上下文context

mostRecentCall .calls.mostRecent() 最近一次被調用的上下文信息           

jasmine.Clock.useMock jasmine.clock().install 啟動模擬時間  

jasmine.Clock.tick jasmine.clock().tick 模擬向前毫秒

  jasmine.clock().uninstall() 停止模擬時間,1.3無此方法

 

 

 

 

 

 

 

 

 

 

 

 

  

 

  

 

 

 

  

 

  先寫這些,其他區別如果有必要,我會在後續的文章中補充。沒有必要我會加一些jasmine2.0的源碼分析文章。

發佈留言