【问题标题】:How to spy on function calling other function in Jasmine?如何监视调用 Jasmine 中其他函数的函数?
【发布时间】:2016-05-19 04:40:37
【问题描述】:

我有问题:

var async = require('async');

function a() {
  async.series([b,c], function(err) {
    console.log('Done');
  });
};
function b(next) {
  next();
};
function c(next) {
  next();
};

var methods = {
  a: a,
  b: b,
  c: c
};

我正在尝试编写这样的测试:

spyOn(methods.a);
methods.a();
expect(methods.b).toHaveBeenCalled();
expect(methods.c).toHaveBeenCalled();

但是 b 和 c 都没有注册为已被调用。任何想法如何正确测试这种行为?

【问题讨论】:

    标签: javascript testing asynchronous jasmine


    【解决方案1】:

    如果您对函数或方法使用 spy,那么 Jasmine 将查看此函数以检查调用它。 Jasmine Spy 下调用的函数默认不执行其代码。

    spyOn(methods, "a");
    methods.a();
    expect(methods.a).toHaveBeenCalled();
    

    在您的情况下,您需要检查异步代码执行。我们可以用done函数来做到这一点:

    it("should support async execution", function(done) {
        var MAX_ASYNC_DELAY = 2000;
        spyOn(methods, "b");
        spyOn(methods, "с");
        methods.a();
        setTimeout(function(){
            expect(methods.b).toHaveBeenCalled();
            expect(methods.c).toHaveBeenCalled();
            done();
        }, MAX_ASYNC_DELAY );
    });
    

    如果在methods.a() 中你将使用下一个,它将起作用:

    function a() {
         async.series([methods.b, methods.c], function(err) {
              console.log('Done');
         });
    }
    

    如果这样的调整是不可能的,你应该重写测试用例如下:

    it("should support async execution", function(done) {
        var MAX_ASYNC_DELAY = 2000;
        spyOn(window, "b");
        spyOn(window, "с");
        methods.a();
        setTimeout(function(){
            expect(b).toHaveBeenCalled();
            expect(c).toHaveBeenCalled();
            done();
        }, MAX_ASYNC_DELAY );
    });
    

    Owen Ayres 建议不要在测试用例中使用setTimeout。但是,如果您使用 Jasmine,这在您的情况下是不可能的。因为jasmine.DEFAULT_TIMEOUT_INTERVAL 是超时等待调用done 函数。 例如,您的异步超时等于接近 10000 毫秒,而您将 MAX_ASYNC_DELAY 设置为 11000 毫秒。测试用例将被标记为失败,因为默认情况下jasmine.DEFAULT_TIMEOUT_INTERVAL 等于 5000 毫秒。需要使用覆盖此参数:

    var originalTimeout;
    beforeEach(function() {
        originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
        jasmine.DEFAULT_TIMEOUT_INTERVAL = 12000; // ms to wait for done()
    });
    it("should support async execution", function(done) {
        var MAX_ASYNC_DELAY = 11000;
        // test case from above
    });
    afterEach(function() {
        jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
    });
    

    如果你使用 Jasmine 2.2 及以上版本,你可以这样写:

    it("should support async execution", function(done) {
        var MAX_ASYNC_DELAY = 11000;
        // test case from above
    }, 12000);
    

    【讨论】:

      【解决方案2】:

      在单元测试中不惜一切代价避免setTimeout。以下是您应该如何以可读的“三 A 测试”格式对其进行测试。如果从未进行过函数调用,使用 Jasmine 的 async done 将确保它在失败之前等待一段时间。如果你想为这个测试用例定制这个,你可以做一些类似于我在下面的 beforeEach 中定义的事情(但在测试本身内部)。

      beforeEach(function() {
          // these are not required, including to show you can have if desired
          originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
          jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // ms to wait for done()
      });
      
      it('calls methods b and c when a is called', function (done) {
          var a = spyOn(methods.a);
          var b = spyOn(methods.b);
      
          methods.a();
      
          expect(a).toHaveBeenCalled();
          expect(b).toHaveBeenCalled();
          done();
      });
      
      afterEach(function() {
          // could be inline of above test if not needed for multiple cases.
          jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
      });
      

      不要在测试中使用超时。这不是一种干净的测试方式,除非绝对必要,否则应该避免。

      【讨论】:

      • “不要使用超时” --- 你还能怎么拖延? waitsFor 不见了 :( :( :( stackoverflow.com/questions/37310701/…
      • @FizzBu​​zz 我已经回答了你的问题,但你可能想稍微详细说明一下你的代码
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-21
      • 2012-03-09
      • 1970-01-01
      相关资源
      最近更新 更多