如您所知,在单元测试中,它内置的angularjs功能可以使用$ httpBackend模拟XHR请求 - 这在编写单元测试时非常有用且有用。
最近,我遇到了在文件上传的情况下嘲笑XHR并发现一些问题的需要。
请考虑以下代码:
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress(event), false);
xhr.addEventListener("load", uploadComplete(event), false);
xhr.addEventListener("error", uploadError(event), false);
xhr.addEventListener("abort", uploadAbort(event), false);
xhr.open("POST", 'some url');
xhr.send(someData);
我想要做的是通过模拟XHR请求对这样的代码进行单元测试,但是不可能这样做,因为这里没有使用$ http服务。
我尝试了这个(它正在运行,可以使用$ httpBackend进行模拟):
$http({
method: 'POST',
url: 'some url',
data: someData,
headers: {'Content-Type': undefined},
transformRequest: angular.identity})
.then(successCallback, errorCallback);
但在这种情况下,我不知道如何实现'progress'回调和'abort'回调(它们是必不可少的,并且在我现在正在处理的情况下是必需的)。
我已经看到有关最新Angular支持进程回调承诺的信息(不确定它是否与$ http服务集成),但是中止回调呢?
任何想法或者你之前遇到类似的东西?
答案 0 :(得分:11)
如果$http
服务没有为您提供所需的一切,您仍然可以对第一个代码块进行单元测试。首先,更改代码以使用Angular的$window
服务。这只是一个包装器服务,但它允许您在测试中模拟对象。所以,你会想要这样做:
var xhr = new $window.XMLHttpRequest();
然后在你的测试中,只需模仿并使用间谍。
$window.XMLHttpRequest= angular.noop;
addEventListenerSpy = jasmine.createSpy("addEventListener");
openSpy = jasmine.createSpy("open");
sendSpy = jasmine.createSpy("send");
xhrObj = {
upload:
{
addEventListener: addEventListenerSpy
},
addEventListener: addEventListenerSpy,
open: openSpy,
send: sendSpy
};
spyOn($window, "XMLHttpRequest").andReturn(xhrObj);
从那里,您可以让不同的间谍返回您想要的不同测试。
答案 1 :(得分:2)
您应该模拟$http
并控制任何延迟,因为您希望更多地控制您的测试。基本上,模拟$http
提供者并提供一个暴露其延迟的自定义实现,然后使用它。
你不应该担心$http
是否正常工作,因为它应该是,并且已经过测试。所以你必须嘲笑它,并且只担心测试你的部分代码。
你应该这样:
describe('Testing a Hello World controller', function() {
beforeEach(module(function($provide) {
$provide.provider('$http', function() {
this.$get = function($q) {
return function() {
var deferred = $q.defer(),
promise = deferred.promise;
promise.$$deferred = deferred;
return promise;
}
};
});
}));
it('should answer to fail callback', inject(function(yourService, $rootScope) {
var spyOk = jasmine.createSpy('okListener'),
spyAbort = jasmine.createSpy('abortListener'),
spyProgress = jasmine.createSpy('progressListener');
var promise = yourService.upload('a-file');
promise.then(spyOk, spyAbort, spyProgress);
promise.$$deferred.reject('something went wrong');
$rootScope.$apply();
expect(spyAbort).toHaveBeenCalledWith('something went wrong');
}));
});
您的服务很简单:
app.service('yourService', function($http) {
return {
upload: function(file) {
// do something and
return $http({...});
}
};
});
请注意,承诺通知仅适用于最新的RC版本。所以,如果你不能使用它,只需详细说明一下这个例子并模拟XHR事件等等。
另请注意,为了遵循KISS原则,您最好为每个回调(失败,成功和进度)设置一个测试用例。