Jasmine支持在返回的promise之后运行的测试方法逻辑

时间:2015-04-07 15:18:53

标签: javascript angularjs asynchronous jasmine

我有一个我想测试的java脚本方法。它看起来像这样(这是简化的psudocode,原谅错别字)

$scope.savePerson = function(){
      Person.create($scope.person).then(function(newPerson){
          if($scope.person.org){
             Organization.addPerson($scope.person.org, newPerson.id);
          }

     toaster.pop('success', "person added");
}

这是使用restangular,但这个想法很简单。当调用savePerson方法时,它首先保存person对象,一旦该保存完成它,然后尝试将该人员保存到组织,如果组织已设置。在人员出现之前,该组织无法保存。

我想通过为个人和组织创建间谍来测试这种逻辑,然后期望它们都被调用。一个天真的方法可能看起来像这样:

describe( 'save person', function () {
var Person, Organization, person;


beforeEach(inject(function($controller, $q, _Organization_, _Person_) {
   Person=_Person_;
   Organization=_Organization_;
   person={...} //whaver goes here, but include an org

   Person.create=jasmine.createSpy('create()').andCallFake( funciton(newPerson){
       var defer = $q.defer();
       defer.resolve(personParam);
       return defer.promise;
  });

  Organization.addPerson= jasmine.createSpy('addPerson()').andCallFake(funciton(personParam){
     var defer=$q.defer();
     defer.resolve(personParam);
     return defer.promise;
  });

 controllerOptions.Person=Person;
 controllerOptions.Organization=Organization;
 controllerOptions.person=person;
 MyController= $controller('MyController', controllerOptions);
}));

it('adds org if exists', function(){
   $scope.savePerson($scope.person);

  expect(Person.create).toHaveBeenCalled();
  expect(Organization.addPerson).toHaveBeenCalled();
});

这将写入失败,特别是不会调用addPerson。这不是代码中的缺陷,而是线程问题。因为我的代码调用.then on person.create它正在创建一个异步线程来运行。在异步线程启动并运行then逻辑之前,不会调用Organization.addPerson。问题是我的测试在不等待该线程的情况下继续运行,因此它会进入expect调用并失败。

现在一个非常懒的修复方法是在我的测试中添加一个短暂的10毫秒等待。此测试等待异步线程的那一刻将启动,立即获得响应,并调用addPerson。然而,这是关于中断将如何发生的假设的中继,并且不足以进行测试。

我相信我也可以通过让我的origination.addPerson函数设置一些“addPersonCalled”值然后使用仅在设置了addPersonCalled方法时运行的async calls来解决这个问题,但它看起来有点难看。

这似乎是一个常见的用例。我想知道茉莉是否有更清洁的方法来支持这个用例?有没有办法告诉茉莉等待任何当前的事情。那么在继续测试之前,你的承诺要求解决的方法是什么?

1 个答案:

答案 0 :(得分:0)

我们有两种选择。第一种是调用$ timeout.flush()或$ rootScope。$ apply()来解决所有的承诺(Testing AngularJS promises in Jasmine 2.0

然而,这解决了所有承诺,这成为我测试的一个问题,因为我承诺了我还没有想要解决的问题。这部分是由于一些丑陋的黑客可以解决传统程序的问题,这些问题正在逐步消除。

另一个看起来非常有希望的工具(双关语并非故意,诚实!)是模拟承诺:http://pivotallabs.com/testing-javascript-promises/

不幸的是,我还没有使用过该工具,但它看起来很不错。