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:http://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次调用的参数,返回值为[]

it("tracks the arguments of each call", function(){
    foo.setBar(123);
    foo.setBar(456, "baz");
    expect(foo.setBar.calls.argsFor(0)).toEqual([123]);    
    expect(foo.setBar.calls.argsFor(1)).toEqual([456, "baz"]);
});    
.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的源码分析文章。

原文地址:https://www.cnblogs.com/hanyangecho/p/3579321.html