• jasmine —— Spies(转)


    Jasmine有称为间谍(spies)的测试双重功能。一个spy可以监测任何函数的调用和参数的调用痕迹。Spy只能存在于定义它的describe()it()代码块内,而在每一个spec(即it)结束后将被移除。(这个语法在Jasmine2.0才改变的)

    有几个特别的Matchers与spy相互作用: 
    toHaveBeenCalled():在spy被调用是返回true; 
    toHaveBeenCalledTimes():在spy调用指定次数的时候会通过测试; 
    toHaveBeenCalledWith():如果匹配任一调用的参数列表,则返回true。

    例子:

    describe("A spy", function() {
      var foo, bar = null;
    
      beforeEach(function() {
        foo = {
          setBar: function(value) {
            bar = value;
          }
        };
        /*使用spyOn()来声明spy*/
        spyOn(foo, 'setBar');
    
        foo.setBar(123);
        foo.setBar(456, 'another param');
      });
    
        it("tracks that the spy was called", function() {
        /*测试spy是否调用*/
        expect(foo.setBar).toHaveBeenCalled();
      });
        
        it("tracks that the spy was called x times", function() {
        /*测试spy是否调用两次*/
        expect(foo.setBar).toHaveBeenCalledTimes(2);
      });
    
        it("tracks all the arguments of its calls", function() {
        /*测试spy调用时的参数列表是否匹配*/
        expect(foo.setBar).toHaveBeenCalledWith(123);
        expect(foo.setBar).toHaveBeenCalledWith(456, 'another param');
      });
    
        it("stops all execution on a function", function() {
        /*spy的调用并不会影响真实的值,所以bar仍然是null*/
        expect(bar).toBeNull();
      });
    });

    Spy通过链式调用and.callThrough,除了追踪所有的调用之外,它将委托实际的实现值。例如:

     1 describe("A spy, when configured to call through", function() {
     2   var foo, bar, fetchedBar;
     3 
     4   beforeEach(function() {
     5     foo = {
     6       setBar: function(value) {
     7         bar = value;
     8       },
     9       getBar: function() {
    10         return bar;
    11       }
    12     };
    13 
    14     spyOn(foo, 'getBar').and.callThrough();   //定义spy并且链式调用
    15 
    16     foo.setBar(123);
    17     fetchedBar = foo.getBar();   //调用spy
    18   });
    19 
    20   it("tracks that the spy was called", function() {
    21     expect(foo.getBar).toHaveBeenCalled();
    22   });
    23 
    24   it("should not affect other functions", function() {
    25     expect(bar).toEqual(123);
    26   });
    27 
    28   it("when called returns the requested value", function() {
    29     expect(fetchedBar).toEqual(123);   //fetchedBar为函数实际返回的值。
    30   });
    31 });

    将上述代码与以下代码对比:

     1 describe("A spy, when configured to call through", function() {
     2   var foo, bar, fetchedBar;
     3 
     4   beforeEach(function() {
     5     foo = {
     6       setBar: function(value) {
     7         bar = value;
     8       },
     9       getBar: function() {
    10         return bar;
    11       }
    12     };
    13 
    14     spyOn(foo, 'getBar');   //不再链式调用and.callThrough()
    15 
    16     foo.setBar(123);
    17     fetchedBar = foo.getBar();
    18   });
    19 
    20   it("tracks that the spy was called", function() {
    21     expect(foo.getBar).toHaveBeenCalled();
    22   });
    23 
    24   it("should not affect other functions", function() {
    25     expect(bar).toEqual(123);
    26   });
    27 
    28   it("when called returns the requested value", function() {
    29     expect(fetchedBar).toBeUndefined();   //此时的fetchedBar不再是函数返回的实际值,而是undefined
    30   });
    31 });

    Spy通过链式调用and.returnValue,所有调用spy的都将返回一个指定值。例如:

     1 describe("A spy, when configured to fake a return value", function() {
     2   var foo, bar, fetchedBar;
     3 
     4   beforeEach(function() {
     5     foo = {
     6       setBar: function(value) {
     7         bar = value;
     8       },
     9       getBar: function() {
    10         return bar;
    11       }
    12     };
    13 
    14     spyOn(foo, "getBar").and.returnValue(745);   //指定返回745
    15 
    16     foo.setBar(123);
    17     fetchedBar = foo.getBar();
    18   });
    19 
    20   it("tracks that the spy was called", function() {
    21     expect(foo.getBar).toHaveBeenCalled();
    22   });
    23 
    24   it("should not affect other functions", function() {
    25     expect(bar).toEqual(123);
    26   });
    27 
    28   it("when called returns the requested value", function() {
    29     expect(fetchedBar).toEqual(745);   //返回特定值为745
    30   });
    31 });

    Spy通过链式调用and.returnValues,所有调用该spy的函数都将按顺序返回一些特定的值,直到返回值队列的最后,这之后的所有调用将返回undefined。例如:

     1 describe("A spy, when configured to fake a series of return values", function() {
     2   var foo, bar;
     3 
     4   beforeEach(function() {
     5     foo = {
     6       setBar: function(value) {
     7         bar = value;
     8       },
     9       getBar: function() {
    10         return bar;
    11       }
    12     };
    13 
    14     spyOn(foo, "getBar").and.returnValues("fetched first", "fetched second");
    15 
    16     foo.setBar(123);
    17   });
    18 
    19   it("tracks that the spy was called", function() {
    20     foo.getBar(123);
    21     expect(foo.getBar).toHaveBeenCalled();
    22   });
    23 
    24   it("should not affect other functions", function() {
    25     expect(bar).toEqual(123);
    26   });
    27 
    28   it("when called multiple times returns the requested values in order", function() {
    29     expect(foo.getBar()).toEqual("fetched first");  //第一次调用,返回队列的第一个值
    30     expect(foo.getBar()).toEqual("fetched second");  //第二次调用,返回队列的第二个值
    31     expect(foo.getBar()).toBeUndefined();  //之后的调用都将返回undefined
    32   });
    33 });

    Spy通过调用and.callFake,所有调用该spy的都将调用其提供的函数,例如:

     1 describe("A spy, when configured with an alternate implementation", function() {
     2   var foo, bar, fetchedBar;
     3 
     4   beforeEach(function() {
     5     foo = {
     6       setBar: function(value) {
     7         bar = value;
     8       },
     9       getBar: function() {
    10         return bar;
    11       }
    12     };
    13 
    14     spyOn(foo, "getBar").and.callFake(function() {
    15       return 1001;
    16     });
    17 
    18     foo.setBar(123);
    19     fetchedBar = foo.getBar();
    20   });
    21 
    22   it("tracks that the spy was called", function() {
    23     expect(foo.getBar).toHaveBeenCalled();
    24   });
    25 
    26   it("should not affect other functions", function() {
    27     expect(bar).toEqual(123);
    28   });
    29 
    30   it("when called returns the requested value", function() {
    31     expect(fetchedBar).toEqual(1001);
    32   });
    33 });

    Spy链式调用and.throwError,调用该spy的将以一个错误的形式抛出特殊返回值,例如:

     1 describe("A spy, when configured to throw an error", function() {
     2   var foo, bar;
     3 
     4   beforeEach(function() {
     5     foo = {
     6       setBar: function(value) {
     7         bar = value;
     8       }
     9     };
    10 
    11     spyOn(foo, "setBar").and.throwError("quux");
    12   });
    13 
    14   it("throws the value", function() {
    15     expect(function() {
    16       foo.setBar(123)
    17     }).toThrowError("quux");
    18   });
    19 });

    Spy链式调用以上某一个策略后,可以调用and.stub随时返回之前保存的原始数据,而不进行修改。例如:

     1 describe("A spy", function() {
     2   var foo, bar = null;
     3 
     4   beforeEach(function() {
     5     foo = {
     6       setBar: function(value) {
     7         bar = value;
     8       }
     9     };
    10 
    11     spyOn(foo, 'setBar').and.callThrough();
    12   });
    13 
    14   it("can call through and then stub in the same spec", function() {
    15     foo.setBar(123);   //调用策略and.callThrough()所定义的spy
    16     expect(bar).toEqual(123);   //bar数值被修改为123
    17 
    18     foo.setBar.and.stub();   //调用and.stub()
    19     bar = null;
    20 
    21     foo.setBar(123);//调用spy
    22     expect(bar).toBe(null);   //bar不再返回and.callThrough()的实现值
    23   });
    24 });

    其他跟踪属性

    任何调用spy的都将被追踪,并且暴露在calls的属性中。 

    calls属性有:

    1、.calls.any() : 一次都没调用时返回false,一旦调用至少一次就返回true;

    2. .calls.count():返回spy调用的次数

    3. .calls.argsFor(index):返回第index+1次调用时传递的参数,index从0开始;

    4. .calls.allArgs():以数组的形式返回调用时传递的所有参数;

    5. .calls.all():以对象形式返回上下文(this),以及所有传递的参数;

    6. .calls.mostRecent():以对象形式返回最近一次调用的上下文(this),以及传递的参数;

    7. .calls.first():以对象形式返回第一次调用的上下文(this),以及传递的参数;(当检查.calls.all().calls.mostRecent().calls.first()返回的对象时,.object属性指向的是调用该spy的this对象)

    8. .calls.reset():清空spy的所有追踪。

    上述属性值,例子如下:

     1 describe("A spy", function() {
     2   var foo, bar = null;
     3 
     4   beforeEach(function() {
     5     foo = {
     6       setBar: function(value) {
     7         bar = value;
     8       }
     9     };
    10 
    11     spyOn(foo, 'setBar');
    12   });
    13     it("tracks if it was called at all", function() {
    14     expect(foo.setBar.calls.any()).toEqual(false);
    15 
    16     foo.setBar();
    17 
    18     expect(foo.setBar.calls.any()).toEqual(true);
    19   });
    20     it("tracks the number of times it was called", function() {
    21     expect(foo.setBar.calls.count()).toEqual(0);
    22 
    23     foo.setBar();
    24     foo.setBar();
    25 
    26     expect(foo.setBar.calls.count()).toEqual(2);
    27   });
    28     it("tracks the arguments of each call", function() {
    29     foo.setBar(123);
    30     foo.setBar(456, "baz");
    31 
    32     expect(foo.setBar.calls.argsFor(0)).toEqual([123]);
    33     expect(foo.setBar.calls.argsFor(1)).toEqual([456, "baz"]);
    34   });
    35     it("tracks the arguments of all calls", function() {
    36     foo.setBar(123);
    37     foo.setBar(456, "baz");
    38 
    39     expect(foo.setBar.calls.allArgs()).toEqual([[123],[456, "baz"]]);
    40   });
    41     it("can provide the context and arguments to all calls", function() {
    42     foo.setBar(123);
    43 
    44     expect(foo.setBar.calls.all()).toEqual([{object: foo, args: [123], returnValue: undefined}]);
    45   });
    46     it("has a shortcut to the most recent call", function() {
    47     foo.setBar(123);
    48     foo.setBar(456, "baz");
    49 
    50     expect(foo.setBar.calls.mostRecent()).toEqual({object: foo, args: [456, "baz"], returnValue: undefined});
    51   });
    52     it("has a shortcut to the first call", function() {
    53     foo.setBar(123);
    54     foo.setBar(456, "baz");
    55 
    56     expect(foo.setBar.calls.first()).toEqual({object: foo, args: [123], returnValue: undefined});
    57   });
    58     it("tracks the context", function() {
    59     var spy = jasmine.createSpy('spy');
    60     var baz = {
    61       fn: spy
    62     };
    63     var quux = {
    64       fn: spy
    65     };
    66     baz.fn(123);
    67     quux.fn(456);
    68 
    69     //当检查.calls.all(),.calls.mostRecent(),.calls.first()返回的对象时,.object属性指向的是调用该spy的this对象
    70     expect(spy.calls.first().object).toBe(baz);
    71     expect(spy.calls.mostRecent().object).toBe(quux);
    72   });
    73     it("can be reset", function() {
    74     foo.setBar(123);
    75     foo.setBar(456, "baz");
    76 
    77     expect(foo.setBar.calls.any()).toBe(true);
    78 
    79     foo.setBar.calls.reset();
    80 
    81     expect(foo.setBar.calls.any()).toBe(false);
    82   });
    83 });

    Spies:createSpy

    如果没有一个函数可以spyOn,jasmine.createSpy可以创建一个“空白”的spy。该spy会像其他间谍一样追踪调用,函数等等,但是在其之后并不会有实际实现的返回值。Spies是JavaScript对象,可以这样使用:

     1 describe("A spy, when created manually", function() {
     2   var whatAmI;
     3 
     4   beforeEach(function() {
     5     whatAmI = jasmine.createSpy('whatAmI');
     6 
     7     whatAmI("I", "am", "a", "spy");
     8   });
     9 
    10   it("is named, which helps in error reporting", function() {
    11     expect(whatAmI.and.identity()).toEqual('whatAmI');
    12   });
    13 
    14   it("tracks that the spy was called", function() {
    15     expect(whatAmI).toHaveBeenCalled();
    16   });
    17 
    18   it("tracks its number of calls", function() {
    19     expect(whatAmI.calls.count()).toEqual(1);
    20   });
    21 
    22   it("tracks all the arguments of its calls", function() {
    23     expect(whatAmI).toHaveBeenCalledWith("I", "am", "a", "spy");
    24   });
    25 
    26   it("allows access to the most recent call", function() {
    27     expect(whatAmI.calls.mostRecent().args[0]).toEqual("I");
    28   });
    29 });

    Spies:createSpyObj

    为了创建一个多重spies的模拟,使用jasmine.createSpyObj()并传递一个字符串的数组,将会返回一个对象,对象包括每个字符串绑定的spy属性。例如:

     1 describe("Multiple spies, when created manually", function() {
     2   var tape;
     3 
     4   beforeEach(function() {
     5     tape = jasmine.createSpyObj('tape', ['play', 'pause', 'stop', 'rewind']);
     6 
     7     tape.play();
     8     tape.pause();
     9     tape.rewind(0);
    10   });
    11 
    12   it("creates spies for each requested function", function() {
    13     expect(tape.play).toBeDefined();
    14     expect(tape.pause).toBeDefined();
    15     expect(tape.stop).toBeDefined();
    16     expect(tape.rewind).toBeDefined();
    17   });
    18 
    19   it("tracks that the spies were called", function() {
    20     expect(tape.play).toHaveBeenCalled();
    21     expect(tape.pause).toHaveBeenCalled();
    22     expect(tape.rewind).toHaveBeenCalled();
    23     expect(tape.stop).not.toHaveBeenCalled();
    24   });
    25 
    26   it("tracks all the arguments of its calls", function() {
    27     expect(tape.rewind).toHaveBeenCalledWith(0);
    28   });
    29 });
  • 相关阅读:
    面向对象进阶
    初识面向对象
    模块和包
    day 17递归函数
    pip命令无法使用
    Python中的iteritems()和items()
    C# 截取字符串
    Python连接Mysql数据库
    【PYTHON】 Missing parentheses in call to 'print'
    javaScript中with函数用法实例分析
  • 原文地址:https://www.cnblogs.com/xuepei/p/6375215.html
Copyright © 2020-2023  润新知