繁体   English   中英

如何使用Jasmine测试AngularJS中的.catch Promise返回?

[英]How Can I Test a .catch Promise Return in AngularJS using Jasmine?

我对Javascript很新,只是学习AngularJS,但我已经把大部分测试用例都用到了我发现的一些很好的例子。 不幸的是,我似乎无法找到任何东西来帮助我测试我目前的情况。

我正在使用模拟服务测试Controller,其方法返回一个promise。 我希望模拟的服务返回一个错误,以便在控制器方法中执行'.catch'块。 我可以说它在几个方面没有被正确调用:

  1. 我正在使用伊斯坦布尔进行代码覆盖,它告诉我我没有覆盖'捕获'
  2. '.catch'块中的代码没有从我通过调试告诉的内容中执行

正在测试的控制器,特别需要在$ scope.login中测试'.catch':

login.js

'use strict';

angular.module('ibcwebDashApp')
  .controller('LoginCtrl', function ($scope, Auth, $location) {
    $scope.user = {};
    $scope.errors = {};

    $scope.login = function(form) {
      $scope.submitted = true;

      if(form.$valid) {
        Auth.login({
          email: $scope.user.email,
          password: $scope.user.password
        })
        .then( function() {
          // Logged in, redirect to home
          $location.path('/');
        })
        .catch( function(err) {
          err = err.data;
          $scope.errors.other = err.message;
        });
      }
    };
  });

我试图模仿的服务和方法:

Auth.login

'use strict';

angular.module('ibcwebDashApp')
  .factory('Auth', function Auth($location, $rootScope, Session, User, $cookieStore) {

    // Get currentUser from cookie
    $rootScope.currentUser = $cookieStore.get('user') || null;
    $cookieStore.remove('user');

    return {

      /**
       * Authenticate user
       * 
       * @param  {Object}   user     - login info
       * @param  {Function} callback - optional
       * @return {Promise}            
       */
      login: function(user, callback) {
        var cb = callback || angular.noop;

        return Session.save({
          email: user.email,
          password: user.password
        }, function(user) {
          $rootScope.currentUser = user;
          return cb();
        }, function(err) {
          return cb(err);
        }).$promise;
      },

最后,我的测试文件。 有趣的是,所有测试都在通过,但最后一次测试中的“期望”可以改为几乎任何东西而且它仍然通过。 前两个测试似乎按预期运行,但最后一个测试是我试图通过从模拟Auth服务抛出错误来执行catch块:

login.unit.js

'use strict';

describe('Controller: LoginCtrl', function () {
  var $scope, $location, loginCtrl, mockAuthService;


  beforeEach(function() {
    mockAuthService = jasmine.createSpyObj('Auth', ['login']);

    module('ibcwebDashApp');

    module(function($provide) {
      $provide.value('Auth', mockAuthService);
    });

    inject(function($rootScope, $controller, $q, _$location_) {
      //create an empty scope
      $scope = $rootScope.$new();
      $location = _$location_;
      //declare the controller and inject our empty scope
      loginCtrl = $controller('LoginCtrl', {$scope: $scope, Auth: mockAuthService});

    });

  });


  describe('successful login', function() {

    beforeEach(function() {
      inject(function($q) {
        mockAuthService.login.andReturn($q.when());
      });

    });

    it('should call auth.login with the scope email and password when form is valid', function() {
      //given
      $scope.form = {};
      $scope.form.$valid = true;
      $scope.user.email = 'user@test.com';
      $scope.user.password = 'password123';

      //when
      $scope.login($scope.form);

      //then
      expect($scope.submitted).toBe(true);
      expect(mockAuthService.login).toHaveBeenCalledWith({email:'user@test.com', password:'password123'});

      $scope.$apply(); //force return of auth.login promise

      expect($location.path()).toBe('/');
    });

    it('should not call auth.login if form is invalid', function() {
      //given
      $scope.form = {};
      $scope.form.$valid = false;

      //when
      $scope.login($scope.form);

      expect(mockAuthService.login).not.toHaveBeenCalled();
    });
  });

  describe('unsuccessful login', function() {

    beforeEach(function () {
      inject(function () {
        mockAuthService.login.andReturn($q.when(new Error('Bad Login!')));
      });

      it('should set errors.other to the returned auth error message', function() {
        //given
        $scope.form = {};
        $scope.form.$valid = true;

        //when
        $scope.login($scope.form);

        $scope.$apply();

        //then
        expect($scope.errors.other).toEqual('Bad Login!');
      });

    });
  });
});

我为发布这么多代码而道歉,但我想提供尽可能多的上下文。 我非常感谢任何可以帮助我的人,因为我学习了单元测试Angular和承诺的方法! 谢谢!!!

**更新**

我能够通过下面的一些帮助来解决我的问题并发现一些语法错误。 这是解决这个问题的原因:

  1. 我在上一次测试中的beforeEach没有正确关闭,实际上包含了最后一次测试,导致它无法正常运行(或者可能根本没有运行)。 这就是改变期望条件导致没有错误的原因。
  2. 我将我的beforeEach注入更改为: mockAuthService.login.andReturn($q.reject({data: {message: 'Bad Login!'}})); 使用下面建议的reject
  3. 一旦我正确关闭beforeEach我得到一个错误消息,$ q没有定义,所以我不得不将它添加到inject(function($q)

一旦我纠正了这些问题,承诺就被正确拒绝,错误被控制器中的相应代码捕获。

在运行测试之前或同时,模拟部分环境,如下所示:

var originalAuthLogin = Auth.login;
Auth.login = function() {
  return Promise.reject({data: {message: 'Error message'}});
};

测试结束后恢复环境:

Auth.login = originalAuthLogin;

这会立即调用您尝试测试的代码的.catch()块。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM