我如何用 sinon 模拟 angular 的 $http?
How do I mock angular's $http with sinon?
我正在尝试在 Mocha 测试中使用 sinon 对 angular 的 $http 进行简单模拟。
但是无论我怎么尝试,我的间谍都没有任何结果。
searchResource.typeAhead 是我正在测试的函数。它根据参数调用 $http,我想确保请求是正确的。
searchResource.typeAhead returns 一个承诺,但我尝试将检查代码放在 .then() 中,但它永远不会执行。
suite('Search Resource', function() {
var injector = angular.injector(['cannonball-client-search', 'cannonball-client-core']);
var searchResource = injector.get('SearchResource');
suite('#typeAhead()', function () {
setup(function () {
this.server = sinon.fakeServer.create();
this.server.respondWith('GET',
config.endpoints.search.typeAhead,
[200, {'Content-Type': 'application/json'}, '[{ "id": 12, "comment": "Hey there" }]']);
this.spyhttp = sinon.spy(injector.get('$http'));
});
teardown(function () {
this.server.restore();
});
test('positive', function (done) {
searchResource.typeAhead(
'expl',
[{entityType: 'itementity'}],
[{createdBy: 'Eric'}, {createdBy: 'Tal'}],
10
);
this.server.respond();
expect(this.spyhttp.calledWith({
method: 'get',
url: config.endpoints.search.typeAhead +
'?query=expl&filter=entityType:itementity&orfilter=createdBy:Eric&orfilter=createdBy:Tal&limit=10'
})).to.be.true();
done();
});
});
});
Angular 是在考虑测试的情况下构建的。前面的评论并不是说你不能使用 sinon 来模拟 $http,这只是不常见的做法,而且它肯定不会像使用 $httpBackend 那样容易。
我个人只会使用 sinon 来模拟任何不属于 Angular 的依赖项。使用 $httpBackend:
提供模拟响应很容易
$httpBackend.when('GET', '/url').respond({
mock: 'response'
});
现在对“/url”的任何请求都使用模拟响应对象。我确定 $httpBackend 内置了一些其他复杂的魔法来处理其他事情,比如拦截器?
问题出在 Sinon 模拟之外。
如果直接使用 angular.injector
而不是建议的 angular.mock.module
and angular.mock.inject
helpers,则该人自己使用它并了解 Angular 注射器。
明显的缺点是注入器不会在每个规范后自动拆除(当使用 angular.mock.module
时会自动拆除),因此所有嵌套规范都在 [=46 的同一个实例上运行=] 喷油器.
此时
var searchResource = injector.get('SearchResource');
SearchResource
服务实例已经注入未模拟的 $http
,故事到此结束。即使它不会,Angular 也永远不会知道应该使用 this.spyhttp
间谍而不是原始的 $http
服务。它的方法可以在实例化后被窥探
sinon.spy($http, 'get');
但不是 $http
函数本身。
使用angular.injector
进行测试的策略可能是
var $httpSpy;
var injector = angular.injector([
'cannonball-client-search',
'cannonball-client-core',
function ($provide) {
$provide.decorator('$http', function ($delegate) {
return ($httpSpy = sinon.spy($delegate));
});
}
]);
// injector.get('$http') === $httpSpy;
请注意,这将使 Sinon 监视 $http
函数,而不是 its methods。
如果问题是关于如何使用 Sinon 进行 Angular 模拟,那么就这么简单。否则这可能表示 XY 问题,而另一个答案直接解决了它($httpBackend
和 $http
拥抱它的方式正是为了让模拟 XMLHttpRequest 请求的负担不存在)。
我正在尝试在 Mocha 测试中使用 sinon 对 angular 的 $http 进行简单模拟。
但是无论我怎么尝试,我的间谍都没有任何结果。
searchResource.typeAhead 是我正在测试的函数。它根据参数调用 $http,我想确保请求是正确的。
searchResource.typeAhead returns 一个承诺,但我尝试将检查代码放在 .then() 中,但它永远不会执行。
suite('Search Resource', function() {
var injector = angular.injector(['cannonball-client-search', 'cannonball-client-core']);
var searchResource = injector.get('SearchResource');
suite('#typeAhead()', function () {
setup(function () {
this.server = sinon.fakeServer.create();
this.server.respondWith('GET',
config.endpoints.search.typeAhead,
[200, {'Content-Type': 'application/json'}, '[{ "id": 12, "comment": "Hey there" }]']);
this.spyhttp = sinon.spy(injector.get('$http'));
});
teardown(function () {
this.server.restore();
});
test('positive', function (done) {
searchResource.typeAhead(
'expl',
[{entityType: 'itementity'}],
[{createdBy: 'Eric'}, {createdBy: 'Tal'}],
10
);
this.server.respond();
expect(this.spyhttp.calledWith({
method: 'get',
url: config.endpoints.search.typeAhead +
'?query=expl&filter=entityType:itementity&orfilter=createdBy:Eric&orfilter=createdBy:Tal&limit=10'
})).to.be.true();
done();
});
});
});
Angular 是在考虑测试的情况下构建的。前面的评论并不是说你不能使用 sinon 来模拟 $http,这只是不常见的做法,而且它肯定不会像使用 $httpBackend 那样容易。
我个人只会使用 sinon 来模拟任何不属于 Angular 的依赖项。使用 $httpBackend:
提供模拟响应很容易$httpBackend.when('GET', '/url').respond({
mock: 'response'
});
现在对“/url”的任何请求都使用模拟响应对象。我确定 $httpBackend 内置了一些其他复杂的魔法来处理其他事情,比如拦截器?
问题出在 Sinon 模拟之外。
如果直接使用 angular.injector
而不是建议的 angular.mock.module
and angular.mock.inject
helpers,则该人自己使用它并了解 Angular 注射器。
明显的缺点是注入器不会在每个规范后自动拆除(当使用 angular.mock.module
时会自动拆除),因此所有嵌套规范都在 [=46 的同一个实例上运行=] 喷油器.
此时
var searchResource = injector.get('SearchResource');
SearchResource
服务实例已经注入未模拟的 $http
,故事到此结束。即使它不会,Angular 也永远不会知道应该使用 this.spyhttp
间谍而不是原始的 $http
服务。它的方法可以在实例化后被窥探
sinon.spy($http, 'get');
但不是 $http
函数本身。
使用angular.injector
进行测试的策略可能是
var $httpSpy;
var injector = angular.injector([
'cannonball-client-search',
'cannonball-client-core',
function ($provide) {
$provide.decorator('$http', function ($delegate) {
return ($httpSpy = sinon.spy($delegate));
});
}
]);
// injector.get('$http') === $httpSpy;
请注意,这将使 Sinon 监视 $http
函数,而不是 its methods。
如果问题是关于如何使用 Sinon 进行 Angular 模拟,那么就这么简单。否则这可能表示 XY 问题,而另一个答案直接解决了它($httpBackend
和 $http
拥抱它的方式正是为了让模拟 XMLHttpRequest 请求的负担不存在)。