Javascript Jasmine测试以验证回调不会引发错误

Javascript Jasmine测试以验证回调不会引发错误,javascript,asynchronous,jasmine,typeerror,Javascript,Asynchronous,Jasmine,Typeerror,如何编写Jasmine测试来验证异步回调不会引发错误 我正在使用以下基本模式编写函数: myFunction: function (callback) { this.doSomethingAsync(function () { if (callback) { callback(); } }); return "done"; } 参数回调是可选的。因此,如果用户不提供回调,if语句将跳过回调 我想编写一个Jasmine测试,如果

如何编写Jasmine测试来验证异步回调不会引发错误

我正在使用以下基本模式编写函数:

myFunction: function (callback) {
   this.doSomethingAsync(function () {
      if (callback) {
          callback();
      }
    });
    return "done";
 }
参数
回调
是可选的。因此,如果用户不提供回调,
if
语句将跳过回调

我想编写一个Jasmine测试,如果将来有人删除
if
语句,它将失败。然而,我想不出如何构造测试

删除
if
语句并调用
myFunction
的结果是Javascript引发了这个
TypeError

Uncaught TypeError: callback is not a function

但是,我想不出如何设置Jasmine测试来验证没有出现这样的错误。

您可以去掉doSomethingAsync函数,让它只调用回调函数

describe('doSomthingAsync', function(){
  function A(){
    this.doSomethingAsync = function(cb){
      setTimeout(function(){
        cb();
      },2000);
    }
    this.myFunction = function(cb){
      this.doSomethingAsync(function(){
          cb();
      })
    }
  }

  it('tests for the throws', function(){
    var a = new A();
    a.doSomethingAsync = function(cb){
      cb();
    }

    var func = function(){
      a.myFunction();
    };

    var func2 = function(){
      a.myFunction(function(){
        console.log('ping');
      });
    }

    expect(func).toThrow(Error);
    expect(func2).not.toThrow(Error);
  });
});
不过,我可能会通过放置代码来检查回调是否在其他地方定义,从而强制执行回调是可选的这一事实

...
this.doSomethingAsync = function(cb){
    setTimeout(function(){
        if(cb && typeof cb === 'function'){
            cb();
        }
        //do other stuff
    }, 2000)
}

首先,可以通过模拟相关函数以同步执行来序列化异步部分。然后,您可以使用
.not.toThrow()
预期来测试预期的行为

假设此演示对象:

var objUnderTest = {

    doSomethingAsync: function(fn) {
        console.info("Doing something async.");

        setTimeout(function(){
            console.info("Done something async.");
            fn();
        }, 1000);
    },

    myFunction: function(callback) {
        this.doSomethingAsync(function() {
            if (callback) {
                callback();
            }
        });

        return "done";
    }
};
您的测试可能如下所示:

describe("Test", function(){
    beforeEach(function(){
        // serialize calls for easier testing
        // now your closure passed to doSomethingAsync() will directly be called
        spyOn(objUnderTest, "doSomethingAsync").and.callFake(function(fn){
            fn();
        });
    });

    it("should call the callback on myFunction(<callack>)", function() {
        var callback = jasmine.createSpy("callback");
        objUnderTest.myFunction(callback);
        expect(callback).toHaveBeenCalled();
    });

    it("should not throw on myFunction() without callback", function(){
        expect(function(){
            objUnderTest.myFunction();
        }).not.toThrow();
    });
});

在进行karma jasmine测试以检查我的库是否在超时之前没有发生正确的初始化时抛出异常时,我遇到了这个问题。虽然有一个选项可以提供您自己的
setTimeout
,但我想让测试尽可能接近生产条件。我接受了这个

//...some code that sets up eventual failure
var oldOnError = window.onerror;
var thrownMessage: string;
window.onerror = function(msg){
    thrownMessage = msg;
}

window.setTimeout(function(){
  window.onerror = oldOnError;
  expect(thrownMessage).toBeDefined();
  expect(thrownMessage.indexOf("unresolved") > -1).toBe(true);
  done();
}, 100);
在节点中,您可能可以使用它(但尚未测试)


@GaryHayes,什么?传递给函数的变量就是他试图调用的函数。他将函数作为参数,
callback
,并在调用它之前检查它是否存在。如果他删除了
If(callback)
并仍然调用该函数,但调用者没有将函数作为参数传递,他将得到错误
回调不是函数。他做得很好,只是想找个方法写一个测试。但是为什么要担心将来有人会做什么来打破它呢?这要由未来的人来决定。代码按原样工作。这是单元测试的一部分…谢谢你的帮助。我花了一分钟的时间来理解你上面的例子;但是,在我看来,关键的想法是doSomethingAsync存根对于这个测试实际上是同步的。另外,因为我没有寻找特定类型的错误,所以我认为最后一行应该是expect(func2).not.toThrow()。@Zack您是对的,使doSomethingAsync存根同步是一个很大的帮助。然而,Jasmine确实有一个名为
done
的东西,可以用来指示测试何时完成。我的存根的主要目的是扔掉我们不关心的东西。对于测试,我们不关心doSomethingAsync做了什么,我们只关心它在调用回调函数时是否会抛出错误。
//...some code that sets up eventual failure
var oldOnError = window.onerror;
var thrownMessage: string;
window.onerror = function(msg){
    thrownMessage = msg;
}

window.setTimeout(function(){
  window.onerror = oldOnError;
  expect(thrownMessage).toBeDefined();
  expect(thrownMessage.indexOf("unresolved") > -1).toBe(true);
  done();
}, 100);
process.on('uncaughtException', function (err) {
  expect(....);
  done();
})