Javascript 解决Karma单元测试中嵌套的AngularJS承诺

Javascript 解决Karma单元测试中嵌套的AngularJS承诺,javascript,angularjs,karma-jasmine,angular-promise,angularjs-digest,Javascript,Angularjs,Karma Jasmine,Angular Promise,Angularjs Digest,我尝试测试一个使用嵌套承诺的函数(假设此函数无法更改)。要处理这些承诺,我必须调用$rootScope.$digest()至少两次。我想出了一个可行的解决方案,每10毫秒调用一次$digest() // Set some async data to scope.key // Note: This function is just for demonstration purposes. // The real code makes async calls to localForage.

我尝试测试一个使用嵌套承诺的函数(假设此函数无法更改)。要处理这些承诺,我必须调用
$rootScope.$digest()
至少两次。我想出了一个可行的解决方案,每10毫秒调用一次
$digest()

// Set some async data to scope.key
// Note: This function is just for demonstration purposes.
//       The real code makes async calls to localForage.
function serviceCall(scope, key) {
  var d1 = $q.defer(), d2 = $q.defer();

  setTimeout(function () {
    d1.resolve('d1');
  });

  d1.promise.then(function (data) {
    setTimeout(function () {
      d2.resolve(data + ' - d2');
    }, 100); // simulate longer async call
  });

  d2.promise.then(function (data) {
    scope[key] = data;
  });
}

it('nested promises service', function (done) {
  var interval = setInterval(function () {
      $rootScope.$digest();
    }, 10),
    myKey = 'myKey',
    scope = {};

  serviceCall(scope, myKey);

  setTimeout(function () {
    expect(scope[myKey]).toEqual('d1 - d2');
    window.clearInterval(interval);
    done();
  }, 120); // What is the right timeout?
});
问题是估计所需的超时时间,以消化足够的时间来解决所有承诺。如果服务对localstorage等进行真正的异步调用,则会变得更加复杂


还有别的办法解决这个问题吗?是否有办法获得所有剩余的承诺?

您应该使用jasmine spies模拟/剔除任何外部服务调用,以便控制服务何时解析/拒绝。您的服务应该有备份其内部功能的测试

请注意,此示例并不完美,但为了清晰起见,将其缩写

var service = jasmine.createSpyObj('service', ['call']);
var defServiceCall;
var $scope;

beforeEach(function () {
  module('myModule', function ($provide) {
    // NOTE: Replaces the service definition with mock.
    $provide.value('service', service);
  });
  inject(function($q, $rootScope) {
    $scope = $rootScope.$new();
    defServiceCall = $q.defer();
    service.call.and.returnValue(defServiceCall.promise);
  });
});
describe('When resolved', function () {
  beforeEach(function () {
    myFunctionCall(); // Sets myVar on the scope
    defServiceCall.resolve('data');
    $scope.$digest(); // NOTE: Must digest for promise to update
  });
  it('should do something awesome when resolved', function () {
    expect($scope.myVar).toEqual('data');
  });
});

简而言之,没有,真的没有办法估计所需的持续时间;有许多因素参与了这一过程。但是,我很困惑;您直接调用承诺而不是调用实际的异步方法,这似乎很奇怪—您只是在尝试测试.then()功能吗?注意:serviceCall函数中的setTimeout将具有默认延迟(通常为4ms)。您还可以使用angular中内置的$timeout和$interval服务,这通常有助于避免直接调用$root.$digest()或$apply()。只需强调一下,您的整个方法似乎是错误的。你真的不应该试图“猜测”超时应该使用什么数字,特别是如果你正在尝试测试某个东西(随机性是你在测试中应该小心的东西)——有一些角度上的方法可以让你完全避免陷入这种情况。如果你有兴趣听到你如何做到这一点,让我知道,并给我一些具体的细节,你试图测试。谢谢
serviceCall()
只是一个简单的例子。真正的代码调用并使用这些承诺/回调。我可以使用
$timeout
和promises注入一个
localfound
的模拟,但我真的很想用
localfound
库来测试它。它看起来像这样,就像真正的代码一样。修复它们并为一个非嵌套的承诺编写测试。@RetoAebersold是的,但如果这样做了,那么每个延迟应该只包装一个API方法。为每个方法()创建一个helper函数,这样您就只能使用承诺返回函数。然后不要再使用延迟,特别是在结合两个对API的调用时,如您的示例中所示。而且,从文件来看,似乎是开箱即用,所以根本不需要使用任何延期?!