angularjs angularjs-http angular-mock

angularjs - Cómo simular una llamada $ http angular y devolver un objeto de promesa que se comporta como $ http



angularjs-http angular-mock (5)

¿Hay una manera de devolver un HttpPromise (o algo similar) para imitar una llamada a $http ? Quiero establecer una variable global que indique si se realiza la solicitud HTTP real o si se devuelve un objeto HttpPromise falso con datos falsos.

Por ejemplo, tengo un servicio que es similar a este:

angular .module(''myservice'') .factory(''MyService'', [''$http'', function($http) { return { get : function(itemId) { if (isInTestingMode) { // return a promise obj that returns success and fake data } return $http.get("/myapp/items/" + itemId); } }; } ]);

Y en mi controlador, tengo una llamada al servicio mencionado que se parece a esto:

// Somewhere in my controller MyService.get($scope.itemId) .success(function(data) { $scope.item = data; }) .error(function(data, status, headers, config) { $scope.notFound = true; });

Estoy tratando de no cambiar el código del controlador; Quiero que el success y el encadenamiento de error sigan funcionando cuando esté en "isInTestMode". ¿Es posible falsificar un HttpPromise de la manera que describí en el servicio?

A continuación se muestra una edición revisada del "MyService" anterior (un fragmento de código) que contiene un success y un error en el objeto de promesa. Pero, ¿cómo ejecuto el método del success ?

return { get : function(itemId) { if (isInTestingMode) { var promise = $.defer().promise; // Mimicking $http.get''s success promise.success = function(fn) { promise.then(function() { fn({ itemId : "123", name : "ItemName"}, 200, {}, {}); }); return promise; }; // Mimicking $http.get''s error promise.error = function(fn) { promise.then(null, function(response) { fn("Error", 404, {}, {}); }); return promise; }; return promise; } return $http.get("/myapp/items/" + itemId); } }


¡pan comido!

Puedes hacerlo usando angular-mocks-async así:

var app = ng.module( ''mockApp'', [ ''ngMockE2E'', ''ngMockE2EAsync'' ]); app.run( [ ''$httpBackend'', ''$q'', function( $httpBackend, $q ) { $httpBackend.whenAsync( ''GET'', new RegExp( ''http://api.example.com/user/.+$'' ) ).respond( function( method, url, data, config ) { var re = /.*//user//(/w+)/; var userId = parseInt(url.replace(re, ''$1''), 10); var response = $q.defer(); setTimeout( function() { var data = { userId: userId }; response.resolve( [ 200, "mock response", data ] ); }, 1000 ); return response.promise; }); }]);


Encontré que este post es similar a lo que estaba preguntando.

Sin embargo, quería una manera de burlar mi llamada de servicio para que se pudieran devolver datos falsos en lugar de emitir una verdadera llamada de solicitud HTTP. La mejor manera de manejar esta situación, para mí, es usar el servicio $httpBackend angular. Por ejemplo, para omitir una solicitud GET a mi recurso de "artículos" PERO para no omitir GET de mis parciales / plantillas, haría algo como esto:

angular .module(''myApp'', [''ngMockE2E'']) .run([''$httpBackend'', function($httpBackend) { $httpBackend .whenGET(/^partials//.+/) .passThrough(); $httpBackend .whenGET(/^//myapp//items//.+/) .respond({itemId : "123", name : "ItemName"}); }]);

Consulte esta documentación para obtener más información sobre $ httpBackend.


Finalmente encontré una forma de utilizar jasmin . $httpBackend no era una opción para mí, ya que también existían métodos que no eran $ http que necesitaba simular en el mismo servicio. También creo que la prueba del controlador que necesita especificar la url no es perfecta como imho el controlador y su prueba no debería saberlo.

Así es como funciona:

beforeEach(inject(function ($controller, $rootScope, $q) { scope = $rootScope.$new(); mockSvc = { someFn: function () { }, someHttpFn: function () { } }; // use jasmin to fake $http promise response spyOn(mockSvc, ''someHttpFn'').and.callFake(function () { return { success: function (callback) { callback({ // some fake response }); }, then: function(callback) { callback({ // some fake response, you probably would want that to be // the same as for success }); }, error: function(callback){ callback({ // some fake response }); } } }); MyCtrl = $controller(''MyCtrl'', { $scope: scope, MyActualSvc: mockSvc }); }));


Puedes implementar tu clase FakeHttp:

var FakeHttp = function (promise) { this.promise = promise; this.onSuccess = function(){}; this.onError = function(){}; this.premise.then(this.onSuccess, this.onError); }; FakeHttp.prototype.success = function (callback) { this.onSuccess = callback; /**You need this to avoid calling previous tasks**/ this.promise.$$state.pending = null; this.promise.then(this.onSucess, this.onError); return this; }; FakeHttp.prototype.error = function (callback) { this.onError = callback; /**You need this to avoid calling previous tasks**/ this.promise.$$state.pending = null; this.promise.then(this.onSuccess, this.onError); return this; };

Luego, en su código, devolvería un nuevo FakeHttp fuera de la promesa.

if(testingMode){ return new FakeHttp(promise); };

La promesa debe ser asíncrona, de lo contrario no funcionará. Para eso puedes usar $ timeout.


Solo usa el método deferred del servicio $q

var fakeHttpCall = function(isSuccessful) { var deferred = $q.defer() if (isSuccessful === true) { deferred.resolve("Successfully resolved the fake $http call") } else { deferred.reject("Oh no! Something went terribly wrong in you fake $http call") } return deferred.promise }

Y luego puede llamar a su función como una promesa $http (tiene que personalizar lo que quiera poner dentro de ella, por supuesto).

fakeHttpCall(true).then( function (data) { // success callback console.log(data) }, function (err) { // error callback console.log(err) })