Nano Hash - криптовалюты, майнинг, программирование

Тест Karma/Jasmine для ионного приложения, не вводящего контроллер

Я добавляю несколько тестов в ионное приложение, используя Karma и Jasmine. В данный момент я пытаюсь провести тесты для контроллера входа в систему angular. Однако, похоже, он не выполняет вводные предложения, которые создают контроллер и издеваются над всеми внешними зависимостями. Вот код, который я использую:

login.controller.js

(function() {
  var app = angular.module("myApp");

  app.controller("LoginController", function($translate, $state, $ionicPopup, $localStorage, sessionService, userService) {
    var vm = this;

    vm.email = null;
    vm.password = null;

    vm.login = function() {
      $localStorage.email = vm.email;
      $localStorage.password = vm.password;

      sessionService.login().then(
        function(data) {
          if (userService.isAuthenticated()) {
            // User is logged, go to the next state
            $state.go("next_state");
          } else {
            // User is not logged (invalid credentials), show an alert message
            var alertPopup = $ionicPopup.alert({
              title: $translate.instant("LOGIN_FAIL_TITLE"),
              template: $translate.instant("LOGIN_FAIL_MESSAGE")
            });
          }
        }
      );
    }
  });
})();

логин.controller.tests.js

describe("LoginController", function() {
  var controller,
      deferredLogin,
      translateMock,
      stateMock,
      ionicPopupMock,
      localStorageMock,
      sessionServiceMock,
      userServiceMock;

  beforeEach(module("myApp"));

  beforeEach(module(function($provide, $urlRouterProvider) {
    $provide.value("$ionicTemplateCache", function() {});
    $urlRouterProvider.deferIntercept();
  }));

  beforeEach(inject(function($controller, $q) {
    deferredLogin = $q.defer();

    sessionServiceMock = {
      login: jasmine.createSpy("login spy")
                    .and.returnValue(deferredLogin.promise)
    };

    translateMock = jasmine.createSpyObj("$translate spy", ["instant"]);

    stateMock = jasmine.createSpyObj("$state spy", ["go"]);

    ionicPopupMock = jasmine.createSpyObj("$ionicPopup spy", ["alert"]);

    localStorageMock = jasmine.createSpyObj("$localStorage spy", ["getItem"]);

    userServiceMock = jasmine.createSpyObj("userService spy", ["isAuthenticated"]);

    controller = $controller("LoginController", {
      "$translate": translateMock,
      "$state": stateMock,
      "$ionicPopup": ionicPopupMock,
      "$localStorage": localStorageMock,
      "sessionService": sessionServiceMock,
      "userService": userServiceMock
    });
  }));

  describe("#login", function() {
    beforeEach(inject(function(_$rootScope_) {
      $rootScope = _$rootScope_;
      controller.email = "[email protected]";
      controller.password = "foobarfoo";
      controller.login();
    }));

    it("should call login on sessionService", function() {
      expect(sessionServiceMock.login).toHaveBeenCalledWith("[email protected]", "foobarfoo");
    });

    describe("when the login is executed", function() {
      it("if successful, should change state to next_state", function() {
        deferredLogin.resolve();
        $rootScope.$digest();
        expect(stateMock.go).toHaveBeenCalledWith("next_state");
      });

      it("if unsuccessful, should show a popup", function() {
        deferredLogin.reject();
        $rootScope.$digest();
        expect(ionicPopupMock.alert).toHaveBeenCalled();
      });
    });
  });
});

Я искал во всех местах, пробуя разные решения, которые я нашел, но всегда получаю одни и те же результаты:

...
PhantomJS 2.1.1 (Linux 0.0.0) LoginController #login should call login on sessionService FAILED
    forEach@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24
    loadModules@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12
    createInjector@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30
    workFn@/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60
    loaded@http://localhost:9876/context.js:151:17
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53
    forEach@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24
    loadModules@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12
    createInjector@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30
    workFn@/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60
    loaded@http://localhost:9876/context.js:151:17
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53
    TypeError: undefined is not an object (evaluating 'sessionServiceMock.login') in unit-tests/controllers/login.controller.tests.js (line 63)
    unit-tests/controllers/login.controller.tests.js:63:32
    loaded@http://localhost:9876/context.js:151:17
PhantomJS 2.1.1 (Linux 0.0.0) LoginController #login when the login is executed if successful, should change state to capture_image FAILED
    forEach@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24
    loadModules@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12
    createInjector@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30
    workFn@/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60
    loaded@http://localhost:9876/context.js:151:17
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53
    forEach@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24
    loadModules@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12
    createInjector@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30
    workFn@/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60
    loaded@http://localhost:9876/context.js:151:17
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53
    TypeError: undefined is not an object (evaluating 'deferredLogin.resolve') in unit-tests/controllers/login.controller.tests.js (line 68)
    unit-tests/controllers/login.controller.tests.js:68:22
    loaded@http://localhost:9876/context.js:151:17
PhantomJS 2.1.1 (Linux 0.0.0) LoginController #login when the login is executed if unsuccessful, should show a popup FAILED
    forEach@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24
    loadModules@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12
    createInjector@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30
    workFn@/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60
    loaded@http://localhost:9876/context.js:151:17
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53
    forEach@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24
    loadModules@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12
    createInjector@/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30
    workFn@/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60
    loaded@http://localhost:9876/context.js:151:17
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53
    TypeError: undefined is not an object (evaluating 'deferredLogin.reject') in unit-tests/controllers/login.controller.tests.js (line 74)
    unit-tests/controllers/login.controller.tests.js:74:22
    loaded@http://localhost:9876/context.js:151:17
...

Я не могу понять, что я делаю неправильно. Заранее спасибо.

ОБНОВЛЕНИЕ:

Как говорит Мэтью Грин, я изменил способ написания тестов. Теперь они следуют его рекомендациям, и я также добавил еще несколько необходимых инъекций:

describe("LoginController", function() {
  var controller,
      stateMock,
      ionicPopupMock,
      localStorageMock,
      sessionServiceMockPromise,
      sessionServiceMock;

  // Load the application module
  beforeEach(module("myApp"));

  // Avoid trying to load all templates of the application
  beforeEach(module(function($provide, $urlRouterProvider) {
    $provide.value("$ionicTemplateCache", function() {});
    $urlRouterProvider.deferIntercept();
  }));

  // Avoid asynchronous loader of the translations (problem with the angular-translate-design)
  beforeEach(module(function($provide, $translateProvider) {
    $provide.factory("customLoader", function($q) {
      return function() {
        var deferred = $q.defer();
        deferred.resolve({});
        return deferred.promise;
      };
    });

    $translateProvider.useLoader("customLoader");
  }));

  // Instanciate and initialize the controller and mocks
  beforeEach(inject(function($controller, $q) {
    sessionServiceMockPromise = $q.defer();
    sessionServiceMock = jasmine.createSpyObj("sessionServiceMock", ["login"]);
    sessionServiceMock.login.and.callFake(function() {
      return sessionServiceMockPromise.promise;
    });

    stateMock = jasmine.createSpyObj("$state spy", ["go"]);

    ionicPopupMock = jasmine.createSpyObj("$ionicPopup spy", ["alert"]);

    localStorageMock = jasmine.createSpyObj("$localStorage spy", ["getItem"]);

    controller = $controller("LoginController", {
      "$state": stateMock,
      "$ionicPopup": ionicPopupMock,
      "$localStorage": localStorageMock,
      "sessionService": sessionServiceMock
    });
  }));

  describe("#login", function() {
    beforeEach(inject(function(_$rootScope_) {
      $rootScope = _$rootScope_;
      controller.login();
      sessionServiceMockPromise.resolve();
    }));

    it("should call login on sessionService", function() {
      expect(sessionServiceMock.login).toHaveBeenCalledWith();
    });

    describe("when the login is executed", function() {
      it("if successfull, should change state to capture_image", inject(function(userService) {
        spyOn(userService, "isAuthenticated").and.callFake(function() { return true; });
        $rootScope.$digest();
        expect(stateMock.go).toHaveBeenCalledWith("nextState");
      }));

      it("should show a popup", inject(function(userService) {
        spyOn(userService, "isAuthenticated").and.callFake(function() { return false; });
        $rootScope.$digest();
        expect(ionicPopupMock.alert).toHaveBeenCalled();
      }));
    });
  });
});

  • undefined is not an object здесь не имеет смысла. Phantomjs имеет тенденцию проглатывать сообщения об ошибках. Попробуйте запустить его в другом браузере (Chrome) и проверьте ошибки. 26.07.2016

Ответы:


1

Похоже, ваша sessionService.login() — это функция, которая должна возвращать обещание. В этом случае я вижу несколько проблем с тем, что у вас есть.

Во-первых, я не знаю, почему вы решили настроить эту службу иначе, чем остальные. Это может быть, скорее всего, некоторые из ваших проблем. Если вы настроите его так же, как и другие, он будет выглядеть примерно так.

var sessionServiceMockPromise = $q.defer();
sessionServiceMock = jasmine.createSpyObj('sessionServiceMock', ['login']);
sessionServiceMock.login.and.callFake(function() {
    return sessionServiceMockPromise.promise;
});

В этом мы устанавливаем, что логин — это функция, которая возвращает обещание. С помощью sessionServiceMockPromise теперь вы можете вызывать sessionServiceMockPromise.resolve([data]) (или reject() в этом отношении) в своих тестах, чтобы увидеть результат вашего обещания.

Во-вторых, ваш тест говорит, что он ожидает, что логин будет вызываться с двумя переменными. Нигде в вашем коде ни для службы, ни для теста я не вижу, что это функция, которая принимает переменные. Лучшим тестом может быть просто то, что он вызывается или что состояние установлено на то, что вы ожидаете.

26.07.2016
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..