Ошибка типа: service.getForums() не является функцией — модульное тестирование jasmine для AngularJS

#angularjs #unit-testing #jasmine #karma-jasmine

#angularjs #модульное тестирование #jasmine #карма-jasmine

Вопрос:

Привет, я новичок в AngularJS. Я пытаюсь протестировать службу angular ForumService . Для этого я должен имитировать ответ, который я получаю при вызове метода service. Я что-то сделал, но я не знаю, правильно это или нет. Я получаю сообщение об ошибке

«ForumService должен использовать сбой функции»
«Ошибка типа: service.getForums не является функцией»

Это сервис, который я тестирую

 (function() {
  'use strict';

  function ForumService($q, $http, config, Forum) {
    var service = {};

    /**
     * Sends a GET request to backend API for all forums.
     *
     * @return {Promise}
     */
    service.getForums = function(onSuccessCallback, onErrorCallback) {

      $http.get(config.apiBaseUrl   '/api/forums')
        .then(
          function handleSuccess(response) {
            onSuccessCallback(response.data.data);
          },
          function handleError(response) {
            onErrorCallback(response.data.error);
          }
        );
    };
    /**
     * Sends a GET request to backend API for all forums.
     *
     * @return {Promise}
     */
    service.getForumsPromise = function() {
      var q = $q.defer();

      $http.get(config.apiBaseUrl   '/api/forums')
        .then(
          function success(response) {
            q.resolve(buildForumArray(response.data.data));
          },
          function error(response) {
            q.reject(response.data.error);
          }
        );

      return q.promise;
    };

    function buildForumArray(data) {
      var forumArray = [];

      data.forEach(function(forumData) {
        forumArray.push(new Forum(forumData));
      });

      return forumArray;
    }

    return service;
  }

  ForumService.$inject = [
    '$q',
    '$http',
    'config',
    'Forum'
  ];

  angular
    .module('app.services')
    .factory('ForumService', ForumService);
})();  

Ниже приведен код, в котором я тестирую первый метод service.getForums()

 'use strict';

describe('ForumService', function() {

  var service, $q, config, httpBackend;
  beforeEach(module('app.services'));
  beforeEach(module('app.models'));

  beforeEach(module(function($provide) {

    $provide.service('config', function() {

      this.apiBaseUrl = "localhost";

    });

    $provide.service('ForumService', function() {

      this.constructor = jasmine.createSpy('ForumService')

    });

    $provide.service('Forum', function() {

      this.constructor = jasmine.createSpy('Forum')
    });
  }));

  //2.
  beforeEach(function() {


    inject(function($injector) {
      service = $injector.get('ForumService');
      httpBackend = $injector.get('$httpBackend');
      $q = $injector.get('$q');

    });

  });


  // 5. make sure no expectations were missed in your tests.
  afterEach(function() {
    httpBackend.verifyNoOutstandingExpectation();
    httpBackend.verifyNoOutstandingRequest();
  });


  it('should use Function', function() {


    var returnData = [

      {
        id: 1,
        name: "Programming Questions",
        description: "Please post all Questions you have in regards to programming here"
      }, {
        id: 2,
        name: "OOP",
        description: "Object Oriented Programming"
      }
    ];


    console.info('foo');
    httpBackend.when('GET', 'localhost/api/forums').respond(200, returnData);

    service.getForums().then(function(response) {
      console.info(response); // to see the response
      expect(response.data.id).toBe(1);
      expect(response.data.name).toBe("Programming Questions");
      expect(response.data.description).toBe("Please post all Questions you have in regards to programming here");
    });

    httpBackend.flush();


  });

});  

И это мой класс модели

 (function() {
  'use strict';

  angular
    .module('app.models')
    .factory('Forum', Forum);

  Forum.$inject = [];

  function Forum() {
    /**
     * Forum prototype (constructor function).
     *
     * @param data
     * @constructor
     */
    function Forum(data) {
      var self = this;

      if (angular.isDefined(data)) {
        self.id = data.id;
        self.name = data.name;
        self.description = data.description;
      } else {
        self.id = 0;
        self.name = '';
        self.description = '';
      }
    }

    return Forum;
  }
})();  

Ответ №1:

Было много проблем с тестовыми примерами и написанным вами кодом. Исправлены некоторые из них здесь

Прочитайте встроенные комментарии для объяснений

Это должно быть определение вашего getForums метода:

 service.getForums = function(onSuccessCallback, onErrorCallback) {
    $http.get(config.apiBaseUrl   '/api/forums').then(function handleSuccess(response) {
        // You'll get the data inside response.data and not response.data.data
        // onSuccessCallback(response.data.data);
        onSuccessCallback(response.data);
    }, function handleError(response) {
        onErrorCallback(response.data.error);
    });
};
  

Если вы действительно хотели вернуть обещание из getForumsPromise метода, вы могли бы просто сделать это:

 service.getForumsPromise = function() {
    return $http.get(config.apiBaseUrl   '/api/forums');
};
  

$http.get promise в любом случае возвращает a .

И вот как вы должны писать тестовый пример:

 'use strict';

describe('ForumService', function() {

    var returnData = [{
        id: 1,
        name: "Programming Questions",
        description: "Please post all Questions you have in regards to programming here"
    }, {
        id: 2,
        name: "OOP",
        description: "Object Oriented Programming"
    }];

    //Below line of code is not required.
    // var service, $q, config, httpBackend;
    beforeEach(module('app.services'));
    beforeEach(module('app.models'));

    beforeEach(module(function($provide) {
        $provide.service('config', function() {
            this.apiBaseUrl = "localhost";
        });

        // Below line of code is not required.
        // $provide.service('ForumService', function() {
        //     this.constructor = jasmine.createSpy('ForumService')
        // });

        // $provide.service('Forum', function() {
        //     this.constructor = jasmine.createSpy('Forum')
        // });
    }));

    //2.
    // Instead of injecting the services like this
    // beforeEach(function() {
    //     inject(function($injector) {
    //         service = $injector.get('ForumService');
    //         httpBackend = $injector.get('$httpBackend');
    //         $q = $injector.get('$q');
    //     });
    // });

    // Inject them like this
    beforeEach(inject(function(_ForumService_, _$httpBackend_) {
        ForumService = _ForumService_;
        $httpBackend = _$httpBackend_;

        $httpBackend.when('GET', 'localhost/api/forums').respond(200, returnData);
    }))

    // 5. make sure no expectations were missed in your tests.
    afterEach(function() {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    it('should use Function', function() {
        // This data should be outside a specific it block so that it could be reused.
        // Moved it outside.
        // var returnData = [{
        //     id: 1,
        //     name: "Programming Questions",
        //     description: "Please post all Questions you have in regards to programming here"
        // }, {
        //     id: 2,
        //     name: "OOP",
        //     description: "Object Oriented Programming"
        // }];

        console.info('foo');

        // This should be inside beforeEach block so that it could be reused.
        // httpBackend.when('GET', 'localhost/api/forums').respond(200, returnData);

        // You call httpBackend's flush right after the call to your service's method and then expect.
        // Also your expectations are wrong. So you might get errors.
        // Fixing those.
        // service.getForums().then(function(response) {
        //     console.info(response); // to see the response
        //     expect(response.data.id).toBe(1);
        //     expect(response.data.name).toBe("Programming Questions");
        //     expect(response.data.description).toBe("Please post all Questions you have in regards to programming here");
        // });

        // httpBackend.flush();

        // Like this.
        var successCallback = function(data) {
            expect(data.length).toEqual(2);
            expect(data[0].id).toBe(1);
            expect(data[0].name).toBe("Programming Questions");
            expect(data[0].description).toBe("Please post all Questions you have in regards to programming here");
        }

        var errorCallback = function(error) {

        }

        ForumService.getForums(successCallback, errorCallback);

        $httpBackend.flush();
    });
});
  

Надеюсь, это поможет