У меня есть такая угловая фабрика:

.factory('widgetFactory', ['$http', function($http){
  function getWidgets(){
    return $http.get('http://example.com/api/widgets/')
     .then(function(response){
        return response;
     });
  }
  return {
    getWidgets:getWidgets
  };
}])

А у меня есть такой жасминовый тест:

describe('widgetFactory', function ($q) {
  var mockHttp,
  fakeResponse = 'response'
  beforeEach(function() {

    mockHttp = {
      get: jasmine.createSpy('get spy').and.callFake(function () {
        var deferred = $q.defer();
        deferred.resolve(fakeResponse);
        return deferred.promise;
      })
    };

    module(function ($provide) {
      $provide.value('$http', mockHttp);
    });

  });

  it('should call api when getWidgets is called', inject(function (widgetFactory) {
    var result;
    widgetFactory.getWidgets().then(function(response){
      result = response;
    });
    expect(mockHttp.post).toHaveBeenCalledWith('http://example.com/api/widgets/');
    expect(result).toBe(fakeResponse);
  }));
});

Но я получаю следующую ошибку: description не ожидает параметра done .

Я думаю, это может быть связано с тем, как я использую $ q в своем тесте (в других примерах, которые я видел, есть inject(function($q){ ... внутри beforeEach, но я не могу из-за того, что использую module внутри beforeEach, так как это дает мне следующую ошибку: Инжектор уже создан, не удается зарегистрировать модуль!)

Любые идеи?

2
Andy 20 Янв 2016 в 15:23

2 ответа

Вы не можете ввести метод описания. Здесь я переработал вашу версию, чтобы использовать ngMock и избавиться от mockHttp. Надеюсь, это немного объясняет, как работает ngMock

describe('widgetFactory', function () {
  var mockHttp,
  fakeResponse = 'response',
  getWidgetsDefer,
  getWidgetsPromise,
  $httpBackend,
  widgetFactory,
  $q;

  beforeEach(module('plunker'));

  beforeEach(inject(function($injector) {
    $httpBackend = $injector.get('$httpBackend');
    $q = $injector.get('$q');
    widgetFactory = $injector.get('widgetFactory');
  }));

  beforeEach(function() {
    getWidgetsDefer = $q.defer();

    $httpBackend.when('GET', 'http://example.com/api/widgets/')
      .respond(getWidgetsDefer);

    getWidgetsPromise = widgetFactory.getWidgets();
  });

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

  it('should call api when getWidgets is called', inject(function (widgetFactory) {
    expect($httpBackend.flush).not.toThrow();
  }));
});

Вы можете найти плункер здесь

2
Ruben Nagoga 20 Янв 2016 в 18:46

Функция 'done' - это аргумент, который ожидается в блоках Jasmine, но не в describe, в этом смысл ошибки. Сервисы Angular не могут быть внедрены без оболочки inject, потому что Жасмин не знает о них, и проблема не может быть решена, просто игнорируя этот факт.

angular.mock.module может имитировать службы с аргументом объекта , нет необходимости заново изобретать колесо.

К сожалению, имитируемые сервисы должны быть самодостаточными, и это не решит проблему с $q, поэтому его нужно добавить дополнительно после module:

  var $q;
  beforeEach(function() {

    module({
      $http: { ... }
    });

    inject(function (_$q_) {
      $q = _$q_;
    });
  })

К счастью, ngMock предоставляет макет $ httpBackend, так что насмешка $http - это бессмысленно. Фактически, настоящий запрос не должен (и не может) выполняться с помощью ngMock. Спецификация службы виджетов становится такой же тонкой:

widgetFactory.getWidgets();
$httpBackend.expect('GET', 'http://example.com/api/widgets/').respond(fakeResponse);
expect($httpBackend.flush).not.toThrow();

Обратите внимание, что не имеет значения, был ли запрос имитирован до или после вызова $http.get, запросы решаются при вызове $httpBackend.flush(). И проверку fakeResponse === fakeResponse тоже можно спокойно пропустить.

1
Estus Flask 20 Янв 2016 в 18:36