Jasmine测试对象的状态对Ajax方法的间谍调用

时间:2015-07-24 16:58:34

标签: javascript ajax angularjs unit-testing jasmine

我正在对Angular控制器进行单元测试,该控制器使用Rails Resource工厂来处理来自Rails应用程序的GETing和POSTing模型数据。 POST通过模型上的方法完成,例如(使用模型$scope.resource):

$scope.resource.update().then(successHandler, failureHandler);

我有这个方法的间谍来存根Ajax调用,所以我可以对控制器进行单元测试:

resUpdateSpy = spyOn($scope.resource, 'update').and.callFake(function() { 
  return {then: function(success, failure){ success(resUpdateResponse); }};
});

在我的一个控制器方法中,我希望使用某些数据(特别是条带数据)对资源进行POST。在POST之后,数据将以相同的方法被覆盖,因此我无法在之后测试模型的状态。理想情况下,我想要像:

expect($scope.resource.update).toHaveBeenCalled().whileValueOf($scope.resource.stripeKey).isEqualTo('tok123');

显然,香草茉莉花中不存在这种方法。在调用给定的间谍时,Jasmine(通过vanilla或通过第三方项目)是否有办法测试值的状态?还是有另一种方法来测试这种情况 - 特别是模型在数据POST之前的状态 - 我错过了吗?

我在Angular 1.3.14 app上使用Teaspoon 1.0.2运行Jasmine 2.2.0。

2 个答案:

答案 0 :(得分:3)

你可以添加自己的jasime匹配器,你需要的那个

jasmine.Matchers.prototype.toBeResolvedWith = function() {
  var done, expectedArgs;
  expectedArgs = jasmine.util.argsToArray(arguments);
  if (!this.actual.done) {
    throw new Error('Expected a promise, but got ' + jasmine.pp(this.actual) + '.');
  }
  done = jasmine.createSpy('done');
  this.actual.done(done);
  this.message = function() {
    if (done.callCount === 0) {
      return ["Expected spy " + done.identity + " to have been resolved with " + jasmine.pp(expectedArgs) + " but it was never resolved.", "Expected spy " + done.identity + " not to have been resolved with " + jasmine.pp(expectedArgs) + " but it was."];
    } else {
      return ["Expected spy " + done.identity + " to have been resolved with " + jasmine.pp(expectedArgs) + " but was resolved with " + jasmine.pp(done.argsForCall), "Expected spy " + done.identity + " not to have been resolved with " + jasmine.pp(expectedArgs) + " but was resolved with " + jasmine.pp(done.argsForCall)];
    }
  };
  return this.env.contains_(done.argsForCall, expectedArgs);
};

此处更多https://gist.github.com/gr2m/2191748

评论后

更新:

基本上jasmine支持自定义匹配器。建立匹配器中的一些是toBe,toEqual等。您可以添加自己的custom matcher来检查承诺。

var customMatchers = {

toHaveBeenResolved: function(util, customEqualityTesters) {
  return {
    compare: function(actual, expected) {
      var result = {};
      // do you comparison logic here
      result.pass = true/false;
      result.message = 'some message about test result';
      return result;
    }
}

this.actual是一个承诺,您可以像这样解决它

result = {};
promise.then(function(value){
  result.value = value;
  result.status = 'Resolved';
}, function(value){
  result.value = value;
  result.status = 'Rejected';
});

一旦声明了自定义匹配器,就会在beforeEach回调中的测试用例中使用它。

beforeEach(function() {
  jasmine.addMatchers(customMatchers);
}); 

答案 1 :(得分:1)

正如你已经让你的间谍转发了一个伪造的函数,让那个假函数为你存储感兴趣的值:

var scopeResourceStripeKeyDuringSpyCall = '(spy not called, yet)';
resUpdateSpy = spyOn($scope.resource, 'update').and.callFake(function() {
  scopeResourceStripeKeyDuringSpyCall = $scope.resource.stripeKey;
  return {then: function(success, failure){ success(resUpdateResponse); }};
});

然后只需检查断言中存储的值:

expect(scopeResourceStripeKeyDuringSpyCall).toEqual('tok123');

(根据间谍设置和断言是否在同一范围内,用于存储值的变量可能必须更少本地。)