AngularJS中的模拟后端服务器(Google Forms)

时间:2014-11-24 09:05:36

标签: angularjs unit-testing mocking httprequest karma-jasmine

我正在使用AngularJs控制器将数据从表单发送到Google表单。使用Jasmine我写了单元测试,这引起了下面的问题:

Error: Unsatisfied requests: POST http://localhost:5000/google-form
at Function.$httpBackend.verifyNoOutstandingExpectation 
(.../angular-mocks/angular-mocks.js:1474:13)

在google搜索并在stackowerflow中浏览了一些questions之后,我决定发布这个问题,因为我找不到解决方案。

以下是您参考的代码:

角度控制器

/* global $ */
'use strict';
angular.module('myApp')
  .controller('QuickMessageCtrl', ['$scope', function ($scope) {
    $scope.quickMessageButtonText = 'Send';
    $scope.quickMessage = {
      name: '',
      email: '',
      content: '',
    };

    function setSubmittingIndicators() {
      $scope.quickMessageButtonText = '';
      $scope.submitting = true;
    }

    $scope.postQuickMessageToGoogle = _.throttle(function() {
      setSubmittingIndicators();
      $.ajax({
        url: 'https://docs.google.com/forms/d/MyFormKey/formResponse',
        data: {
          'entry.3'  : $scope.quickMessage.name,
          'entry.1'  : $scope.quickMessage.email,
          'entry.0'  : $scope.quickMessage.content
        },
        type: 'POST',
        dataType: 'jsonp',
        statusCode: {
          200: function (){
            //show succes message;
          }
        }
      });
    }, 500);
  }]);

单元测试代码

'use strict';

describe('Controller: QuickMessageCtrl', function() {
    var $httpBackend, $rootScope, $controller, scope, apiUrl; 

    beforeEach(module('myApp'));

    beforeEach(inject(function($injector) {
        $httpBackend = $injector.get('$httpBackend');
        apiUrl = $injector.get('apiUrl');
        $httpBackend.expect(
            'POST',
            apiUrl + 'google-form',
            {'name': 'test', 'email': 'test@test.com', 'content': 'this is content'}
        ).respond(200);

        $rootScope = $injector.get('$rootScope');
        scope = $rootScope.$new();
        $controller = $injector.get('$controller');
        $controller('QuickMessageCtrl', { $scope: scope });
    }));

    afterEach(function() {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    describe('Successful form submit', function() {
        beforeEach(function() {
            scope.quickMessageForm = { $valid: true };
            scope.quickMessage.email = 'test@test.com';
            scope.quickMessage.name = 'test';
            scope.quickMessage.content = 'this is test';
            scope.postQuickMessageToGoogle();
        });

        it('should set submitting indicators on submit', function() {
            expect(scope.quickMessageButtonText).toBe('');
        });

    });
});

2 个答案:

答案 0 :(得分:2)

您的测试表明模拟http后端应该在URL

处收到POST
apiUrl + 'google-form'

,如果出现错误消息,则为http://localhost:5000/google-form

但是您的控制器永远不会向该URL发送POST。它向https://docs.google.com/forms/d/MyFormKey/formResponse发送POST。它并没有使用angular的$ http服务,而是使用jQuery在它的背后。

答案 1 :(得分:1)

正如@JB Nizet指出的那样,你使用的是jQuery而不是angular方法。实际上你应该重构一下你的代码。

它是一个great practice来保持分离,比如Controller from Service。在您的情况下,您在控制器内使用服务。我宁愿建议您创建一个服务,然后在您的控制器中导入该服务。所以基本上代码如下:

<强>控制器

/* global $ */
'use strict';
angular.module('myApp')
  .controller('QuickMessageCtrl', ['$scope', 'MyNewService', function ($scope, MyNewService) {
    $scope.quickMessageButtonText = 'Send';
    $scope.quickMessage = {
      name: '',
      email: '',
      content: '',
    };

    function resetFormData() {
      $('#name').val('');
      $('#email').val('');
      $('#content').val('');
    }

    $scope.postQuickMessageToGoogle = _.throttle(function() {
      setSubmittingIndicators();
      MyNewService.sendQuickMessage(
        $scope.quickMessage.name,
        $scope.quickMessage.email,
        $scope.quickMessage.content
      )
      .success(
        //sucess Message
        //can be as well a function that returns a status code
      )
      .error(
        //error Message
      );
    }, 500);
  }]);

<强>服务

'use strict';
angular.module('myApp')
  .factory('MyNewService', ['$http', function ($http) {
    var myService = {};

    myService.sendQuickMessage = function(name, email, content) {
      $http({
        method: 'JSONP',
        url: 'https://docs.google.com/forms/d/MyFormKey/formResponse?'+
          'entry.3=' + name +
          '&entry.1=' + email +
          '&entry.0=' + content
      });
    };
    return myService;
  }]);

<强>单元测试

'use strict';

describe('Controller: QuickMessageCtrl', function() {
  var $httpBackend, $rootScope, $controller, scope, apiUrl;

  beforeEach(module('myApp'));

  beforeEach(inject(function($injector) {
    $httpBackend = $injector.get('$httpBackend');
    apiUrl = $injector.get('apiUrl');
    $httpBackend.expectJSONP(
      'https://docs.google.com/forms/d/MyFormKey/formResponse?'+
      'entry.3=test'+
      '&entry.1=test@test.com'+
      '&entry.0=thisIsContent'
    ).respond(200, {});

    $rootScope = $injector.get('$rootScope');
    scope = $rootScope.$new();
    $controller = $injector.get('$controller');
    $controller('QuickMessageCtrl', { $scope: scope });
  }));

  describe('form submit', function() {
    var changeStateSpy;
    beforeEach(function() {
      scope.quickMessage.name = 'test';
      scope.quickMessage.content = 'thisIsContent';
      scope.quickMessage.email ='test@test.com';
    });

    afterEach(function(){
      $httpBackend.verifyNoOutstandingExpectation();
      $httpBackend.verifyNoOutstandingRequest();
    });

    it('should set submitting indicators on submit', function() {
      scope.postQuickMessageToGoogle();
      expect(scope.quickMessageButtonText).toBe('');
      $httpBackend.flush();
    });
  });
});