Jasmine 支持在返回的 promise 之后运行的测试方法逻辑
Jasmine support for testing method logic that runs after a returned promise
我有一个 java 脚本方法要测试。它看起来像这样(这是简化的伪代码,请原谅打字错误)
$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 方法时,它首先保存人员对象,一旦保存完成,它就会尝试将人员保存到组织 if 组织已设置。在人员被保存之前,组织无法保存。
我想通过为个人和组织创建间谍然后期望他们都被调用来测试这个逻辑。天真的方法可能看起来像这样:
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。这不是代码中的缺陷,而是线程的问题。因为我的代码在 person.create 上调用 .then,它正在为 运行 创建一个异步线程。 Organization.addPerson 在异步线程启动之前不会被调用,然后逻辑是 运行 .问题是我的测试继续 运行ning 而没有等待该线程,因此它到达预期调用并失败。
现在一个非常懒惰的修复方法是在我的测试中添加一个短暂的 10 毫秒等待。该测试等待异步线程的那一刻将启动,立即获得响应并调用 addPerson。然而,这是基于中断将如何发生的假设,并且不够严格以进行测试。
我相信我也可以通过让我的 origination.addPerson 函数设置一些 "addPersonCalled" 值然后使用 async calls 来解决这个问题 运行s 只有在 addPersonCalled 方法是设置好了,就是有点丑
这似乎是一个常见的用例。我想知道 jasmine 是否有更简洁的方法来支持这个用例?有什么方法可以告诉 jasmine 在继续测试之前等待任何当前的 .then 方法调用你的承诺来解决?
我们有两种选择。第一个是调用 $timeout.flush() 或 $rootScope.$apply() 这将解决所有的承诺 (Testing AngularJS promises in Jasmine 2.0)
然而,这解决了 所有 承诺,这成为我测试的一个问题,因为我有我不想解决的承诺。这部分是由于一些丑陋的黑客来解决遗留程序的问题,该遗留程序正在完全删除。
另一个看起来相当……有前途的工具(不是双关语,老实说!)是 Mock-promises:http://pivotallabs.com/testing-javascript-promises/
不幸的是,我还没有开始使用这个工具,但它看起来很不错。
我有一个 java 脚本方法要测试。它看起来像这样(这是简化的伪代码,请原谅打字错误)
$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 方法时,它首先保存人员对象,一旦保存完成,它就会尝试将人员保存到组织 if 组织已设置。在人员被保存之前,组织无法保存。
我想通过为个人和组织创建间谍然后期望他们都被调用来测试这个逻辑。天真的方法可能看起来像这样:
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。这不是代码中的缺陷,而是线程的问题。因为我的代码在 person.create 上调用 .then,它正在为 运行 创建一个异步线程。 Organization.addPerson 在异步线程启动之前不会被调用,然后逻辑是 运行 .问题是我的测试继续 运行ning 而没有等待该线程,因此它到达预期调用并失败。
现在一个非常懒惰的修复方法是在我的测试中添加一个短暂的 10 毫秒等待。该测试等待异步线程的那一刻将启动,立即获得响应并调用 addPerson。然而,这是基于中断将如何发生的假设,并且不够严格以进行测试。
我相信我也可以通过让我的 origination.addPerson 函数设置一些 "addPersonCalled" 值然后使用 async calls 来解决这个问题 运行s 只有在 addPersonCalled 方法是设置好了,就是有点丑
这似乎是一个常见的用例。我想知道 jasmine 是否有更简洁的方法来支持这个用例?有什么方法可以告诉 jasmine 在继续测试之前等待任何当前的 .then 方法调用你的承诺来解决?
我们有两种选择。第一个是调用 $timeout.flush() 或 $rootScope.$apply() 这将解决所有的承诺 (Testing AngularJS promises in Jasmine 2.0)
然而,这解决了 所有 承诺,这成为我测试的一个问题,因为我有我不想解决的承诺。这部分是由于一些丑陋的黑客来解决遗留程序的问题,该遗留程序正在完全删除。
另一个看起来相当……有前途的工具(不是双关语,老实说!)是 Mock-promises:http://pivotallabs.com/testing-javascript-promises/
不幸的是,我还没有开始使用这个工具,但它看起来很不错。