【问题标题】:Testing if a method returns an Promise测试方法是否返回 Promise
【发布时间】:2014-05-29 12:24:48
【问题描述】:

在angularjs中,在测试服务时,我想检查返回的对象是否是Promise。

现在我正在做以下事情 -

 obj.testMethod()
        .should.be.instanceOf($q.defer());

【问题讨论】:

标签: angularjs unit-testing promise


【解决方案1】:

您可以模拟 $http 并让它返回您创建的一些对象。然后您可以检查您的服务是否返回该对象。

【讨论】:

  • testMethod 返回一个 HttpPromise,带有成功和错误方法。我不想松开它们。
  • 如果你检查一下(对象有成功和错误方法的事实),这还不够吗?
  • 目前我正在做你提到的事情。但如果我可以通过instanceOf 方法进行测试,那就太好了。你不这么认为吗?
  • 这取决于您认为您的服务的 API 是什么。它是返回“一个承诺”还是返回一个具有 then 和 success 和 error 函数的对象。 “承诺”的定义是什么?您不是用类型语言编写代码,这就是为什么很难测试返回对象的类型...请查看stackoverflow.com/questions/3379529/duck-typing-in-javascript
【解决方案2】:

查看源代码中的第 248 行 $q (https://github.com/angular/angular.js/blob/master/src/ng/q.js#L248) 并没有真正的检查可以确定。这将是你最好的选择

var deferred = method();

if(angular.isObject(deferred) && 
   angular.isObject(deferred.promise) && 
   deferred.promise.then instanceof Function && 
   deferred.promise["catch"] instanceof Function && 
   deferred.promise["finally"] instanceof Function){
   //This is a simple Promise
}

如果promise实际上是一个可以使用new Promise()的函数,那么你可以使用promise instanceof Promise,但是它是一个对象,所以它没有任何特殊标识符,你唯一可以测试的就是它们特性。

编辑

要测试“HttpPromise”,您可以添加在$http 服务(https://github.com/angular/angular.js/blob/master/src/ng/http.js#L726)中定义的errorsuccess 的检查:

var promise = $http(...);

if(angular.isObject(promise) && 
   promise.then instanceof Function && 
   promise["catch"] instanceof Function && 
   promise["finally"] instanceof Function && 
   promise.error instanceof Function && 
   promise.success instanceof Function){
   //This is a HttpPromise
}

额外

如果您注意到 $http 实际上并没有返回 deferred,它会返回直接的承诺,如果您按照调用它实际上返回 $q.when(...) 并添加了几个函数。你可以看到$q.when 没有返回deferred,而是返回$q.deferred().promise,所以反过来$http(...) 永远不会是$q.deferred()

另外,如果您要运行您发布的测试,我希望您会收到此错误:

TypeError: Expecting a function in instanceof check, but got #<Object>

【讨论】:

  • 上面的代码仍然没有检查 HttpPromise 这不是真正的 $q 承诺。对吗?
  • 很确定它们是一样的,不是吗?它返回 $q.when 并添加成功和错误承诺声明:github.com/angular/angular.js/blob/master/src/ng/http.js#L707,承诺修改为添加成功和错误:github.com/angular/angular.js/blob/master/src/ng/http.js#L726
  • 感谢您指向源代码。这绝对有用。
  • 开源项目的好处在于,您可以深入了解一切情况。您使用什么框架进行测试?这是真正的方法还是伪代码?我会假设$q.deffered(); 的新“实例”会丢失一些,尤其是成功和错误功能。这意味着它们不会“相等”,可以这么说,但它们仍然是承诺
  • 不应该推迟,而不是推迟吗?
【解决方案3】:

测试一个对象是否是一个promise很简单:

return !!obj.then && typeof obj.then === 'function';

就是这样。如果一个对象有then 方法,它就是一个promise。

看起来 Angular 的 $q 与其他类型的 Promise 没有任何区别。

【讨论】:

  • 我认为这是更正确的方法,因为 $q 本身会将带有.then 的任何内容视为承诺。
  • 为什么投反对票?在大多数情况下,它看起来是最有用的答案。
  • 也许还检查obj.then.length === 2 在第一次验证它是一个函数之后。 Promise 的 .then() 方法应该有两个形式参数(一个解析处理程序和一个拒绝处理程序),并且函数的 .length 属性应该返回该函数接受的形式参数的数量。
  • @idbehold 这可能不是最好的主意 - 考虑一个具有 3 个参数(一个用于进度)的 Angular $q 或 Q 承诺或 jQuery deferred。
  • @BenjaminGruenbaum 好的,obj.then.length >= 2.
【解决方案4】:

我正在处理回调,我需要点击事件的 CTA 来触发函数并确定触发的回调类型,这里有一些简单的示例。

let fn = function () { alert('A simple function') };

let cta = fn();

console.log(cta instanceof Promise);

// logs false

新的承诺示例

let fn = function () {

    return new Promise(function (accept, reject) {

        accept();

        // reject();

    });

};

let cta = fn();

if(cta instanceof Promise) {

    cta.then(function () {

        alert('I was a promise');

    });

}

Axios 示例 1

let fn = function () {

   return axios.get('/user');

}

let cta = fn();

if(cta instanceof Promise) {

    cta.then(function () {

        alert('I was a promise from axios');

    });

}

// Triggers alert('I was a promise from axios');

Axios 示例 2

let fn = function () {

   return axios.get('/user').then(response => {
       console.log('user response', response.data);
   });

}

let cta = fn();

if(cta instanceof Promise) {

    cta.finally(function () {

        alert('I was a final promise from axios');

    });

}

// Triggers alert('I was a final promise from axios');

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 1970-01-01
    • 2016-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多