使用 Jasmine 模拟 Angular http 响应不进入回调函数
Mocking Angular http response with Jasmine doesn't enter callback function
我试图在我的 Jasmine 测试中模拟来自 Angular 的 http 调用的一些响应。
我有一项名为 'ImageService' 的服务,它有一个名为 'create' 的功能。我正在监视创建并返回一个被拒绝的承诺,因为我正在尝试测试错误。
这是我的服务:
this.create = function(image) {
return imageApi.post(image);
};
imageApi 变量是一个 Restangular 实例。
我的测试是这样的:
spyOn(ImageService, 'create').and.callFake(function () {
var deferred = $q.defer();
deferred.reject({
data: {
status: 400,
errors: {
"image.fileNotImage": "File uploaded is not an image."
}
}
});
return deferred.promise;
});
虽然我拒绝了这个承诺,但它并没有进入我的控制器的错误回调。来自我的控制器的调用看起来像这样。
ImageService.create(formData)
.then(function(response) {
console.log(response);
vm.imagePreview = response;
createAdMedia(adMedia, response.fileURL);
}, function(error) {
console.log(error);
/**
* If we get no data then we can assume its a 500 or
* 405 error so we give a generic error message
*/
if (error.data.errors) {
var errors = error.data.errors;
for (var key in errors) {
showMessage("errorMessage", DWIN.i18n.t(errors[key]));
}
} else {
showMessage("errorMessage", DWIN.i18n.t("merchant.admedia.failure"));
}
});
有人能看出这个问题吗?
谢谢!
您没有给出测试的完整代码,但我怀疑您在调用服务函数后省略了执行 $digest() 或 $apply() 的操作。否则 angular 将不会执行它通常执行的任何自动化功能,因为您处于测试环境中而不是 运行 应用程序。
这是一个示例,说明如何更简单地将 $q 与 $digest() 结合使用,假设您正在测试使用此 create
方法的控制器:
beforeEach(inject(function ($rootScope, $controller, _$q_, _YourService_) {
$scope = $rootScope.$new();
$q = _$q_;
YourService = _YourService_;
YourController = $controller('YourController', { $scope: $scope });
}));
it('Should do something', function () {
spyOn(YourService, 'create').and.returnValue($q.reject({data: yourdata}));
YourController.theMethodThasUsesCreate();
$scope.$digest();
expect(something).toHaveBeenCalled();
});
一些概念证明,无需对所有内容/方法进行存根。
angular.module('image', [])
.service('ImageService', function($q) {
this.create = function() {
return $q.when();
}
})
.controller('ImageCtrl', function(ImageService) {
ImageService.create()
.then(function(response) {}, function(error) {
console.error('error', error);
});
});
describe('ImageCtrl', function() {
var $scope;
beforeEach(module('image'))
beforeEach(inject(function($rootScope) {
$scope = $rootScope.$new()
}))
it('ImageService.create() - supports rejection', inject(function($controller, $q, ImageService) {
var errorMessage = {data: {error: 'some error message'}}
spyOn(ImageService, 'create').and.returnValue($q.reject(errorMessage))
spyOn(console, 'error')
$controller('ImageCtrl', {
$scope: $scope
});
$scope.$digest();
expect(console.error).toHaveBeenCalledWith('error', errorMessage)
}))
})
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-mocks.js"></script>
我试图在我的 Jasmine 测试中模拟来自 Angular 的 http 调用的一些响应。
我有一项名为 'ImageService' 的服务,它有一个名为 'create' 的功能。我正在监视创建并返回一个被拒绝的承诺,因为我正在尝试测试错误。
这是我的服务:
this.create = function(image) {
return imageApi.post(image);
};
imageApi 变量是一个 Restangular 实例。
我的测试是这样的:
spyOn(ImageService, 'create').and.callFake(function () {
var deferred = $q.defer();
deferred.reject({
data: {
status: 400,
errors: {
"image.fileNotImage": "File uploaded is not an image."
}
}
});
return deferred.promise;
});
虽然我拒绝了这个承诺,但它并没有进入我的控制器的错误回调。来自我的控制器的调用看起来像这样。
ImageService.create(formData)
.then(function(response) {
console.log(response);
vm.imagePreview = response;
createAdMedia(adMedia, response.fileURL);
}, function(error) {
console.log(error);
/**
* If we get no data then we can assume its a 500 or
* 405 error so we give a generic error message
*/
if (error.data.errors) {
var errors = error.data.errors;
for (var key in errors) {
showMessage("errorMessage", DWIN.i18n.t(errors[key]));
}
} else {
showMessage("errorMessage", DWIN.i18n.t("merchant.admedia.failure"));
}
});
有人能看出这个问题吗?
谢谢!
您没有给出测试的完整代码,但我怀疑您在调用服务函数后省略了执行 $digest() 或 $apply() 的操作。否则 angular 将不会执行它通常执行的任何自动化功能,因为您处于测试环境中而不是 运行 应用程序。
这是一个示例,说明如何更简单地将 $q 与 $digest() 结合使用,假设您正在测试使用此 create
方法的控制器:
beforeEach(inject(function ($rootScope, $controller, _$q_, _YourService_) {
$scope = $rootScope.$new();
$q = _$q_;
YourService = _YourService_;
YourController = $controller('YourController', { $scope: $scope });
}));
it('Should do something', function () {
spyOn(YourService, 'create').and.returnValue($q.reject({data: yourdata}));
YourController.theMethodThasUsesCreate();
$scope.$digest();
expect(something).toHaveBeenCalled();
});
一些概念证明,无需对所有内容/方法进行存根。
angular.module('image', [])
.service('ImageService', function($q) {
this.create = function() {
return $q.when();
}
})
.controller('ImageCtrl', function(ImageService) {
ImageService.create()
.then(function(response) {}, function(error) {
console.error('error', error);
});
});
describe('ImageCtrl', function() {
var $scope;
beforeEach(module('image'))
beforeEach(inject(function($rootScope) {
$scope = $rootScope.$new()
}))
it('ImageService.create() - supports rejection', inject(function($controller, $q, ImageService) {
var errorMessage = {data: {error: 'some error message'}}
spyOn(ImageService, 'create').and.returnValue($q.reject(errorMessage))
spyOn(console, 'error')
$controller('ImageCtrl', {
$scope: $scope
});
$scope.$digest();
expect(console.error).toHaveBeenCalledWith('error', errorMessage)
}))
})
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-mocks.js"></script>