Попытка проверить переменную, заданную в обратном вызове

#javascript #angularjs #jasmine #karma-jasmine

#javascript #angularjs #jasmine #карма-жасмин

Вопрос:

Я пытаюсь написать простой тест jasmine для тестирования, который $scope.users устанавливается при обратном Users.find вызове . В моем последнем тесте ниже scope.users значение не определено, поэтому тест завершается неудачно.

Как я могу проверить, что scope.users она установлена, чтобы мой тест прошел?

контроллер

 angular.module('web').controller('CardsCtrl',function($scope, $http, Users){

  /**
   * Get all users on page load
   */
  Users.find(function(users) {

    $scope.users = users;
});
 

Служба пользователей

 (function(window, angular, undefined) {'use strict';

var urlBase = "http://localhost:3333/api";

var module = angular.module("services", ['ngResource']);
module.factory(
  "Users",
  ['LoopBackResource', 'LoopBackAuth', '$injector', function(Resource, LoopBackAuth, $injector) {
    var R = Resource(
      urlBase   "/users/:id",
      { 'id': '@id' },
      {
        "find": {
          url: urlBase   "/users",
          method: "GET",
          isArray: true,
        },
      }
  );

  return R;
}]);
 

спецификация

 describe('CardsCtrl', function() {

  var scope, ctrl, users;

  beforeEach(module('web'));

  beforeEach(inject(function($rootScope, $controller, Users) {
    scope = $rootScope.$new();
    users = Users;
    spyOn(users, 'find');
    ctrl = $controller('CardsCtrl', {$scope: scope, Users: users});
  }));


  describe('the cards controller being instantiated', function() {

    it('should be defined', function() {
      expect(ctrl).toBeDefined();
    });

    it('tracks that the spy was called', function() {
      expect(users.find).toHaveBeenCalled();
    });

    it('fetches user data and assigns it to scope.users', function(done) {
      console.log('users= ' scope.users); // <-- THIS RETURNS UNDEFINED
      expect(scope.users).toBeTruthy();
    });
  });

});
 

Комментарии:

1. Можете ли вы опубликовать код, связанный с пользовательской службой?

2. Это уже есть. Это средний фрагмент кода. Это в значительной степени просто сервис, обернутый вокруг ресурса.

3. Я считаю, что вам нужно использовать $httpBackend для имитации ответа, который вернет ваш сервис.

Ответ №1:

Вам нужно вызвать .andCallThrough() шпиона и использовать $httpBackend для имитации http-ответа:

 describe('CardsCtrl', function() {

    var scope, ctrl, users, httpBackend;

    beforeEach(module('web'));

    beforeEach(inject(function($rootScope, $controller, Users, $httpBackend) {
        scope = $rootScope.$new();
        users = Users;
        spyOn(users, 'find').andCallThrough();
        httpBackend = $httpBackend;
        httpBackend.expectGET(urlBase   '/users').respond(200, ['user1', 'user2']);
        ctrl = $controller('CardsCtrl', {$scope: scope, Users: users});
    }));

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

    describe('the cards controller being instantiated', function() {

        ... // other tests

        it('fetches user data and assigns it to scope.users', function(done) {
            httpBackend.flush();
            expect(scope.users).toBeTruthy();
        });
    });

});
 

Макет $httpBackend предоставляется службой ngMock, поэтому вам необходимо включить angular-mock.js для запуска теста.

Комментарии:

1. Итак, если я использую andCallThrough() , это действительно проходит через мой метод обратного вызова? Что, если у меня было несколько методов обратного вызова, например, успех или неудача? Можете ли вы объяснить, почему мне нужно использовать макет httpBackend?

2. Модульные тесты @Catfish должны выполняться как можно быстрее и не должны зависеть от доступности внешних служб, поэтому вы не хотите делать реальные http-запросы в модульных тестах. Для этой цели создается $httpBackend . Более подробную информацию см. в документах angular: docs.angularjs.org/api/ngMock/service /$httpBackend