$http
の呼び出しを模倣するHttpPromise(または類似の何か)を返す方法はありますか?実際のHTTPリクエストが行われたかどうか、または偽のHttpPromiseオブジェクトが偽のデータとともに返されたかどうかを示すグローバル変数を設定したいと思います。
たとえば、次のようなサービスがあります。
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);
}
};
} ]);
そして、私のコントローラーで、これに似た前述のサービスを呼び出します。
// Somewhere in my controller
MyService.get($scope.itemId)
.success(function(data) {
$scope.item = data;
})
.error(function(data, status, headers, config) {
$scope.notFound = true;
});
notコントローラのコードを変更しようとしています。 「isInTestMode」でsuccess
およびerror
チェーンを引き続き機能させたい。サービスで説明した方法でHttpPromise
を偽造することは可能ですか?
以下は、promiseオブジェクトにsuccess
とerror
を含む、上記の「MyService」(スニペット)の改訂版です。しかし、どのようにして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);
}
}
この投稿 が私が求めていたものと似ていることがわかりました。
しかし、本当のHTTPリクエストコールを発行する代わりに、偽のデータが返されるように、サービスコールをモックする方法が必要でした。私にとって、この状況を処理する最良の方法は、angular's $httpBackend
サービス。たとえば、「items」リソースへのGETリクエストをバイパスするには、notパーシャル/テンプレートのGETをバイパスするには、次のようにします。
angular
.module('myApp', ['ngMockE2E'])
.run(['$httpBackend', function($httpBackend) {
$httpBackend
.whenGET(/^partials\/.+/)
.passThrough();
$httpBackend
.whenGET(/^\/myapp\/items\/.+/)
.respond({itemId : "123", name : "ItemName"});
}]);
$ httpBackendの詳細については このドキュメント を参照してください。
$q
serviceのdeferred
メソッドを使用するだけです
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
}
そして、$http
promiseのように関数を呼び出すことができます(もちろん、その中に置きたいものは何でもカスタマイズする必要があります)。
fakeHttpCall(true).then(
function (data) {
// success callback
console.log(data)
},
function (err) {
// error callback
console.log(err)
})
私はようやく jasminを使用して方法を見つけました 。 $httpBackend
同じサービスでモックが必要な$ http以外のメソッドもあったため、私には選択肢がありませんでした。私はまた、URLを指定する必要があるコントローラーテストは、コントローラーとそのテストがそれについて知る必要がないはずなので、完璧ではないと思います。
以下にその仕組みを示します。
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
});
}));
かんたん簡単!
次のように angular-mocks-async を使用してそれを行うことができます:
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;
});
}]);
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;
};
次に、コードで、約束から新しいfakeHttpを返します。
if(testingMode){
return new FakeHttp(promise);
};
約束は非同期でなければなりません、そうでなければそれは機能しません。そのためには、$ timeoutを使用できます。