AngularJS : 如何正确模拟从 $http 返回的 Promise
AngularJS : How to properly mock a Promise returned from $http
我现在已经为此苦苦挣扎了一段时间,需要一些指导。我想对这个 angular 服务进行单元测试...具体来说,就是 promise 的失败部分。
(function () {
angular.module('testable')
.factory('myService', ["$http", "$q", function ($http, $q) {
return {
createThing: function(thing) {
return $http.post("//...", thing)
.then(function (response) {
return response.data;
}, function (response) {
return $q.reject(response.statusText);
});
}
};
}]);
}());
我浏览过许多关于此的 SO 帖子,但每个帖子似乎都有点不同。首先,如果我的任何服务代码在设置承诺时不正确,请阻止我。我已经通过大约 10 次不同的迭代来测试被拒绝的承诺,但没有任何效果。这是我拥有的:
beforeEach(inject(function ($injector,myService) {
sut = myService;
$httpBackend = $injector.get('$httpBackend');
$q = $injector.get('$q');
$rootScope = $injector.get('$rootScope');
dataToSend = "send me!";
deferred = $q.defer();
}));
it("should get error on error", function () {
var result,
expected = "FAIL!!!!!";
deferred.reject(expected);
$httpBackend.expectPOST(testUrl,dataToSend).respond(deferred.promise);
sut.createThing(dataToSend).then(function (returnFromPromise) {
result = returnFromPromise;
});
$rootScope.$apply();
$httpBackend.flush();
// expect something here but result is always wrong
});
我知道 promises 运行 是异步的...我一直在拼凑一些信息,但是有人对完成这个单元测试有什么建议吗?
当您使用 $httpBackend
服务时,您不需要使用承诺来模拟 HTTP 请求。事实上,respond()
方法具有以下签名:
respond: function(status, data, headers, statusText) {
...
}
要模拟错误,您只需return一个非成功状态代码 (!= 200):
it('should not create a thing', function() {
var result;
// Arrange
$httpBackend.expectPOST('https://domain.com/api')
.respond(500, null, null, 'some error');
// Act
myService.createThing('foo').then(angular.noop, function(data) {
result = data;
});
$httpBackend.flush();
// Assert
expect(result).toBe('some error');
});
下面是涵盖成功和错误案例的完整规范:
describe('Testing a factory', function() {
var myService, $httpBackend;
beforeEach(function() {
module('plunker');
inject(function(_$httpBackend_, _myService_) {
$httpBackend = _$httpBackend_;
myService = _myService_;
})
});
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should create a thing', function() {
var result;
// Arrange
$httpBackend.expectPOST('https://domain.com/api')
.respond(200, 'some data');
// Act
myService.createThing('foo').then(function(data) {
result = data;
});
$httpBackend.flush();
// Assert
expect(result).toBe('some data');
});
it('should not create a thing', function() {
var result;
// Arrange
$httpBackend.expectPOST('https://domain.com/api')
.respond(500, null, null, 'some error');
// Act
myService.createThing('foo').then(angular.noop, function(data) {
result = data;
});
$httpBackend.flush();
// Assert
expect(result).toBe('some error');
});
});
请注意,这里不需要调用 $rootScope.$apply()
,因为不需要摘要循环来更新任何内容。
我现在已经为此苦苦挣扎了一段时间,需要一些指导。我想对这个 angular 服务进行单元测试...具体来说,就是 promise 的失败部分。
(function () {
angular.module('testable')
.factory('myService', ["$http", "$q", function ($http, $q) {
return {
createThing: function(thing) {
return $http.post("//...", thing)
.then(function (response) {
return response.data;
}, function (response) {
return $q.reject(response.statusText);
});
}
};
}]);
}());
我浏览过许多关于此的 SO 帖子,但每个帖子似乎都有点不同。首先,如果我的任何服务代码在设置承诺时不正确,请阻止我。我已经通过大约 10 次不同的迭代来测试被拒绝的承诺,但没有任何效果。这是我拥有的:
beforeEach(inject(function ($injector,myService) {
sut = myService;
$httpBackend = $injector.get('$httpBackend');
$q = $injector.get('$q');
$rootScope = $injector.get('$rootScope');
dataToSend = "send me!";
deferred = $q.defer();
}));
it("should get error on error", function () {
var result,
expected = "FAIL!!!!!";
deferred.reject(expected);
$httpBackend.expectPOST(testUrl,dataToSend).respond(deferred.promise);
sut.createThing(dataToSend).then(function (returnFromPromise) {
result = returnFromPromise;
});
$rootScope.$apply();
$httpBackend.flush();
// expect something here but result is always wrong
});
我知道 promises 运行 是异步的...我一直在拼凑一些信息,但是有人对完成这个单元测试有什么建议吗?
当您使用 $httpBackend
服务时,您不需要使用承诺来模拟 HTTP 请求。事实上,respond()
方法具有以下签名:
respond: function(status, data, headers, statusText) {
...
}
要模拟错误,您只需return一个非成功状态代码 (!= 200):
it('should not create a thing', function() {
var result;
// Arrange
$httpBackend.expectPOST('https://domain.com/api')
.respond(500, null, null, 'some error');
// Act
myService.createThing('foo').then(angular.noop, function(data) {
result = data;
});
$httpBackend.flush();
// Assert
expect(result).toBe('some error');
});
下面是涵盖成功和错误案例的完整规范:
describe('Testing a factory', function() {
var myService, $httpBackend;
beforeEach(function() {
module('plunker');
inject(function(_$httpBackend_, _myService_) {
$httpBackend = _$httpBackend_;
myService = _myService_;
})
});
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should create a thing', function() {
var result;
// Arrange
$httpBackend.expectPOST('https://domain.com/api')
.respond(200, 'some data');
// Act
myService.createThing('foo').then(function(data) {
result = data;
});
$httpBackend.flush();
// Assert
expect(result).toBe('some data');
});
it('should not create a thing', function() {
var result;
// Arrange
$httpBackend.expectPOST('https://domain.com/api')
.respond(500, null, null, 'some error');
// Act
myService.createThing('foo').then(angular.noop, function(data) {
result = data;
});
$httpBackend.flush();
// Assert
expect(result).toBe('some error');
});
});
请注意,这里不需要调用 $rootScope.$apply()
,因为不需要摘要循环来更新任何内容。