Единичное тестирование Угловые заводы, имеющие зависимости

При тестировании устройства Angular factory (с помощью Karma + Jasmine), как я вставляю зависимость stub в тестируемый factory?

Здесь мой factory:

mod = angular.module('myFactoryMod', []);

mod.factory('myFactory', [
  '$log', 'oneOfMyOtherServices', function($log, svc) {
    return makeSomethingThatDoesSomethingWithTheseDependencies($log, svc);
  }
]);

oneOfMyOtherServices требуется при создании экземпляра factory.

Здесь мой тест:

it('can get an instance of my factory', function() {
  var oneOfMyOtherServicesStub;

  angular.mock.module('myFactoryMod');

  oneOfMyOtherServicesStub = {
    someVariable: 1
  };

  //****How do I get my stub in my target? ****

  angular.mock.inject(['myFactory', function(target) {

      expect(target).toBeDefined();

    }
  ]);
})

N.B. Я знаю, что $controller позволяет это для контроллеров, но я не вижу эквивалента для заводов.

Ответ 1

Есть два способа сделать что-то вроде этого, о котором я знаю:

  • Используйте $provide и анонимный модуль для ввода макета.
  • Ввести услугу, которую вы хотели бы высмеять, и использовать функцию шпионажа жасмина для предоставления макетных значений.

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

Использование $provide будет примерно выглядеть так:

describe('myFactory', function () {
  // Load your module.
  beforeEach(module('myFactoryMod'));

  // Setup the mock service in an anonymous module.
  beforeEach(module(function ($provide) {
    $provide.value('oneOfMyOtherServicesStub', {
        someVariable: 1
    });
  }));

  it('can get an instance of my factory', inject(function(myFactory) {
    expect(myFactory).toBeDefined();
  }));
});

Ответ 2

Комментарий @bentsai на самом деле очень полезен для тестирования сервисов; для полноты я добавляю пример.

Вот тест для jasmine, который делает примерно то, что вы ищете. Примечание: для этого требуется включить angular-mocks (это то, что предоставляет такие функции, как module и inject).

describe('app: myApp', function() {
  beforeEach(module('myApp'));
  var $controller;
  beforeEach(inject(function(_$controller_) {
    $controller = _$controller_;
  }));
  // Factory of interest is called MyFactory
  describe('factory: MyFactory', function() {
    var factory = null;
    beforeEach(inject(function(MyFactory) {
      factory = MyFactory;
    }))
    it('Should define methods', function() {
      expect(factory.beAwesome).toBeDefined()
      expect(factory.beAwesome).toEqual(jasmine.any(Function))
    });
  });
});

Это заглушка для определения модуля и связанного с ним определения factory:

var app = angular.module('myApp', []);
app.factory('MyFactory', function() {
  var factory = {};
  factory.beAwesome = function() {
    return 'Awesome!';
  }
  return factory;
});

В этом случае ясно, что использование inject() позволяет вытягивать зависимости, как и ожидалось в вашем обычном приложении angular, и, таким образом, вы можете создавать требования для поддержки тестирования вещей, которые полагаются на них.