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

时间:2015-05-13 20:10:08

标签: javascript asynchronous jasmine uncaught-typeerror

如何编写Jasmine测试以验证异步回调是否引发错误?

我正在用这个基本模式编写一个函数:

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

参数callback是可选的。因此,如果用户没有提供回调,if语句将跳过回调。

如果有人在将来删除if语句,我想写一个Jasmine测试失败。但是,我想不出如何构建测试。

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

Uncaught TypeError: callback is not a function

但是,我无法想到如何设置Jasmine测试以验证是否没有引发此类错误。

3 个答案:

答案 0 :(得分:2)

你可以存根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)
}

答案 1 :(得分:1)

首先,您可以通过将相关函数模拟为同步执行来序列化异步部分。然后,您可以使用.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();
    });
});

由于您只想测试myFunction的行为是否正确,我认为模仿doSomethingAsync即可,即使它是被测模块的一部分也是如此。

如果您不想在测试对象中模拟方法,则可以模拟doSomethingAsync()方法调用的所有方法。

假设您需要模拟演示对象setTimeout()

spyOn(window, "setTimeout").and.callFake(function(fn){
    fn();
});

答案 2 :(得分:0)

我在进行karma-jasmine测试时检查到我的库如果在超时之前没有发生正确的init会抛出异常,我就遇到了这个问题。虽然可以选择提供自己的process.on('uncaughtException', function (err) { expect(....); done(); }) ,但我希望测试尽可能接近prod条件。我选择了这个

Q.ninvoke

在节点中你可以使用它(虽然没有经过测试)

var cuid = require('cuid');
var fs = require('fs');
var Q = require('q');
var AWS = require('aws-sdk');
var S3 = new AWS.S3();

module.exports = {
  initialize: initialize
};

function initialize(options) {
  return Q.nfcall(fs.readFile, options.path).then(function (file) {
    var fileParams = {
      Bucket: options.bucket,
      Key: options.name,
      Body: file,
      ContentType: options.contentType
    };

    return Q.ninvoke(S3, 'upload', fileParams).then(function(data){
      return data.Location;
    });
  });
}