unit-testing - tutorial - pruebas unitarias angular 6
¿Por qué $ también está disponible en la función ''angular.mock.module'', y $ q solo está disponible en la función ''angular.mock.inject''? (2)
Me estoy burlando de un servicio para una prueba de unidad AngularJS. Estoy usando el servicio $provide
para reemplazar el servicio "real" con el mocked out (un script de plunker disponible):
describe(''My Controller'', function () {
var $scope;
var $provide;
beforeEach(angular.mock.module(''myApp''));
beforeEach(angular.mock.module(function (_$provide_) {
$provide = _$provide_;
}));
beforeEach(angular.mock.inject(function($rootScope, $controller, $q){
var mockMyService = {
getAll : function() {
var deferred = $q.defer();
deferred.resolve([
{ itemText: "Foo" },
{ itemText: "Bar" }
]);
return deferred.promise;
}
};
$provide.value(''myService'', mockMyService);
$scope = $rootScope.$new();
$controller(''MyCtrl'', { $scope: $scope });
$rootScope.$apply();
}));
it(''Has two items defined'', function () {
expect($scope.items.length).toEqual(2);
});
});
Esto funciona bien. Sin embargo, no me gusta el hecho de que estoy usando una función angular.mock.module
simplemente para dar una referencia al servicio $provide
angular.mock.inject
que luego se usa en la función angular.mock.inject
continuación. Pero si agrego $provide
un parámetro a la función angular.mock.inject
directamente en su lugar, obtengo un error de "proveedor desconocido".
Se me ocurre que podría poner todo el código de burla en la función angular.mock.module
. Pero luego tengo un problema similar con la referencia $q
, que necesito ya que mi servicio simulado tiene que devolver una promesa.
En otras palabras, si agrego un parámetro $q
a la función angular.mock.module
, también obtengo un error de "proveedor desconocido".
¿Hay alguna manera de simplificar esto? Obviamente, lo que tengo funciona, pero no se siente del todo bien, de alguna manera. Creo que no entiendo por qué algunos proveedores están disponibles en funciones de inject
y otros están disponibles en funciones de module
.
Esto me funcionó cuando tuve que envolver un servicio que usaba $q
y parece bastante limpio:
var _ServiceToTest_;
beforeEach(function () {
module(''module.being.tested'');
module(function ($provide) {
$provide.factory(''ServiceToMock'', function ($q, $rootScope) {
var service = ...;
// use $q et al to heart''s content
return service;
});
});
inject(function (_ServiceToTest_) {
ServiceToTest = _ServiceToTest_;
});
});
it(''...'', function () { /* code using ServiceToTest */ });
El truco consistía en usar $provide.factory
lugar de $provide.value
.
No puede usar $provide
dentro de la función de inject
porque el primero registra a los proveedores para que los use. Echar un vistazo:
describe(''...'', function() {
beforeEach(function() {
module(function($provide) {
$provide.constant(''someValue'', ''foobar'');
});
inject(function(someValue) {
var value = someValue; // will be ''foobar'';
});
});
});
Aunque puedes escribir tu prueba de esta manera:
describe(''...'', function() {
var serviceMock;
beforeEach(function() {
serviceMock = {
someMethod: function() { ... }
};
module(function($provide) {
$provide.value(''service'', serviceMock);
});
inject(function(service) {
...
});
});
});
De hecho, ni siquiera necesita implementar el servicio simulado antes de inyectarlo con $provide
:
beforeEach(function() {
serviceMock = {};
module(function($provide) {
$provide.value(''service'', serviceMock);
});
inject(function(service) {
...
});
});
it(''tests something'', function() {
// Arrange
serviceMock.someMethod = function() { ... }
// Act
// does something
// Assert
expect(...).toBe(...);
});
Aquí hay un script de Plunker que ilustra la mayoría de los anteriores.