【问题标题】:How to handle promise on success or on error如何处理成功或错误的承诺
【发布时间】:2016-09-20 22:28:44
【问题描述】:

我写了一个离子应用程序。我开始向它添加测试我遇到了$resources 的问题。在这种情况下,我有这个控制器:

.controller('newAccountCtrl', function($scope, $window, $rootScope, API, $ionicPopup, $state) {
  $scope.newData = {};
  $scope.$on('$ionicView.enter', function() {

    $scope.newData = {};
  });
  $scope.newInfo = function() {
    API.newAccountInfo.update({
      restCode: $scope.newData.restore_code
    }, $scope.newData, function(res, header) {
      $scope.comty = 'update';
      $window.location.href = '#/login';
    }, function(err) {
      if (err.data == null)
        $rootScope.popup("Error", "no connection");
      else
        $rootScope.popup('error', err.data.error);
    });
  }
})

在服务中,我在函数中使用$resources 发出请求:

angular.module('starter.services', [])
  .factory('API', function($rootScope, $resource, $ionicPopup, $ionicLoading, $window) {
      return {
        newAccountInfo: $resource(base + '/restoreinfo/:restCode', {
          restCode: '@_restCode'
        }, {
          update: {
            method: 'PUT'
          }
        }, {
          stripTrailingSlashes: false
        });
      }

在我的测试中使用以下代码:

describe('newAccountCtrl', function() {

  var controller,
    deferredLogup, window, scope,
    $rootScope,
    $q, store, API,
    PROMISE = {
      resolve: true,
      reject: false
    };
  beforeEach(angular.mock.module('starter'));
  beforeEach(module('starter.controllers'));
  beforeEach(module('starter.services'));
  beforeEach(module(function($provide, $urlRouterProvider) {
    $provide.value('$ionicTemplateCache', function() {});
    $urlRouterProvider.deferIntercept();
  }));

  beforeEach(inject(function($controller, _$rootScope_, $q, _API_, _$window_) {
    $q = $q;

    deferredLogup = $q.defer();
    $rootScope = _$rootScope_;
    spyOn($rootScope, 'popup')
    scope = $rootScope.$new();
    API = _API_;
    window = _$window_;

    spyOn(API.newAccountInfo, 'update').and.callThrough(function(callback) {
      deferredLogup.promise.then(callback);
      return deferredLogup.promise;
    });

    controller = $controller('newAccountCtrl', {
      '$scope': scope,
      'API': API,
      '$window': window
    });

  }));
  it('expect API.newAccountInfo to Have Been Called', function() {
    scope.getloghist();
    expect(API.newAccountInfo.upadate).toHaveBeenCalled();
  })

  it('on success ', function() {
    scope.newInfo();
    deferredLogup.resolve();
    scope.$digest();
    expect(scope.comty).toBeDefined();
  });

  it('on unsuccessful', function() {
    scope.newInfo();
    deferredLogup.reject();
    scope.$digest()
    expect($rootScope.popup).toHaveBeenCalled();
  });
});

第一个期望它通过,但第二个“成功”返回错误

“预期未定义”。

我是编写单元测试的新手。我在这里错过了什么?

【问题讨论】:

    标签: angularjs unit-testing ionic-framework jasmine karma-jasmine


    【解决方案1】:

    在你的间谍中:

    spyOn(API.newAccountInfo, 'update').and.callThrough(function(callback){
      deferredLogup.promise.then(callback);
      return deferredLogup.promise;
    });
    

    .and.callThrough 只跟踪函数。它不会模拟它(因此您传递给它的函数什么也不做)。来自文档:

    通过将间谍与 and.callThrough 链接起来,间谍仍将跟踪对其的所有调用,但此外它还将委派给实际的实现。

    对于“它运行你正在监视的实际功能”来说,这是一个花哨的说法。

    看起来你想要.and.callFake,它使用传递的函数进行跟踪和模拟。

    编辑,因为看起来不止一件事有问题:

    spyOn(API.newAccountInfo,'update').and.callFake(function(callback){
      deferredLogup.promise.then(callback);
      return deferredLogup.promise;
    });
    

    所以,你是在用这个匿名函数模拟:

    function(callback){
      deferredLogup.promise.then(callback);
      return deferredLogup.promise;
    }
    

    这个^ 函数现在充当API.newAccountInfo.update。此函数采用其 first 参数并将其作为回调运行。去看看你在哪里跑API.newAccountInfo.update

    API.newAccountInfo.update({
      restCode: $scope.newData.restore_code
    }, $scope.newData, function(res, header) {
      $scope.comty = 'update';
      $window.location.href = '#/login';
    }, function(err) {
      if (err.data == null)
        $rootScope.popup("Error", "no connection");
      else
        $rootScope.popup('error', err.data.error);
    });
    
    //Simplifying this:
    
    API.newAccountInfo.update([Object], [Object], successCallback, errorCallback)
    

    您将回调作为 thirdfourth 参数而不是第一个参数传递。但是您的模拟正在尝试运行 first 参数。所以它试图将一个对象(而不是一个函数)提供给deferredLogup.promise.then

    你的间谍应该是这样的:

    spyOn(API.newAccountInfo,'update').and.callFake(function(param1, param2, callback, errorCallback){
      deferredLogup.promise.then(callback);
      return deferredLogup.promise;
    });
    

    希望对您有所帮助。

    【讨论】:

    • 你好,我用callFake替换了callThrought,出现同样的错误“Expected undefined to be defined”
    • 我编辑了我的答案。不确定这是否能完全解决您的问题,但它应该让您更接近。
    猜你喜欢
    • 2020-04-11
    • 2015-07-29
    • 1970-01-01
    • 2018-06-01
    • 2015-07-03
    • 2018-09-18
    • 1970-01-01
    • 2016-03-02
    • 1970-01-01
    相关资源
    最近更新 更多