Prueba unitaria de fábricas de AngularJS que tienen dependencias

79

Al realizar pruebas unitarias en una fábrica Angular (con Karma + Jasmine), ¿cómo inyecto una dependencia de stub en la fábrica bajo prueba?

Aquí está mi fábrica:

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

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

oneOfMyOtherServices es necesario al crear una instancia de mi fábrica.

Aquí está mi prueba:

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();

    }
  ]);
})

NB Sé que $controllerpermite esto para los controladores, pero no veo un equivalente para las fábricas.

Roy Truelove
fuente

Respuestas:

93

Hay dos formas de lograr algo como esto que conozco:

  1. Utilice $providey un módulo anónimo para inyectar el simulacro.
  2. Inyecte el servicio que le gustaría simular y use la capacidad de espionaje de jasmine para proporcionar valores simulados.

La segunda opción solo funciona si sabe exactamente qué métodos llamará su código bajo prueba al servicio inyectado y puede simularlos fácilmente. Como parece que está accediendo a una propiedad de datos en el servicio (en lugar de un método), la primera opción podría ser la mejor.

El uso se $providevería aproximadamente así:

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();
  }));
});
Noah Freitas
fuente
Sí, creo que la opción 1 es el camino a seguir. ¡Gracias!
Roy Truelove
7
Me gustaría inyectar myFactory en todas las pruebas. ¿Se puede hacer en un antes de cada uno? Lo intenté pero no funcionó ...
Bennett McElwee
10
Gracias por esta respuesta +1. Sería bueno agregar un ejemplo de código también para la opción # 2, para completar.
klode
2
@BennettMcElwee Sí, puedes. Así: var theFactory; beforeEach(inject(function(myFactory) { theFactory = myFactory; } )));luego úselo theFactoryen su prueba.
bentsai
1
¿Cómo puedo probar este método de fábrica getItemList usando Jasmine y karma? Recibo el error: [$ injector: unpr] errors.angularjs (function () {angular.module ('riskCanvasApp'). Factory ('itemsService', itemsService); itemsService. $ Inject = ['$ http', '$ q ',' $ compile ',' UrlService ',' accountDetailsMainService ',' sharedService ',' authenticationSvc ']; función itemsService ($ http, $ q, $ compile, urlService, accountDetailsMainService, sharedService, authenticationSvc) {
AMRESH PANDEY
12

El comentario de @bentsai es realmente muy útil para probar servicios; para completar, estoy agregando un ejemplo.

Aquí hay una prueba jasmineque hace aproximadamente lo que estás buscando. Nota: esto requiere que hayas angular-mocksincluido (esto es lo que proporciona funciones como moduley 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))
    });
  });
});

Este es un código auxiliar de cómo podrían verse el módulo y la definición de fábrica asociada:

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

En este caso, está claro que el uso de le inject()permite incorporar dependencias, tal como lo esperaría en su aplicación angular normal, y como tal, puede crear requisitos para respaldar las pruebas de cosas que dependen de ellas.

AJ.
fuente
2
Se ha perdido la parte en la que inyecta una dependencia de código auxiliar a MyFactory en las pruebas.
skolsuper
¿Dónde está la segunda dependencia?
Chocó