这是一个单元测试的服务包装$ http,该服务很简单,它只是防止对服务器重复调用,同时确保尝试执行调用的代码仍然获得预期的数据。
angular.module('services') .factory('httpService',['$http',function($http) { var pendingCalls = {}; var createKey = function(url,data,method) { return method + url + JSON.stringify(data); }; var send = function(url,method) { var key = createKey(url,method); if (pendingCalls[key]) { return pendingCalls[key]; } var promise = $http({ method: method,url: url,data: data }); pendingCalls[key] = promise; promise.then(function() { delete pendingCalls[key]; }); return promise; }; return { post: function(url,data) { return send(url,'POST'); },get: function(url,'GET'); },_delete: function(url,'DELETE'); } }; }]);
单元测试也很简单,它使用$ httpBackend来预期请求。
it('does GET requests',function(done) { $httpBackend.expectGET('/some/random/url').respond('The response'); service.get('/some/random/url').then(function(result) { expect(result.data).toEqual('The response'); done(); }); $httpBackend.flush(); });
这被吹了作为done()被调用与“$ digest已经在进行”错误。我不知道为什么。我可以解决这个通过包裹done()在这样的超时
setTimeout(function() { done() },1);
这意味着done()将排队,并运行在$ digest完成后,但同时解决我的问题,我想知道
>为什么Angular在摘要周期中首先?
>为什么调用done()触发这个错误?
我有与Jasmine 1.3运行绿色的完全相同的测试,这只发生在我升级到Jasmine 2.0和重写了测试使用新的异步语法。
据我所知,$ httpBackend.flush()的目的是完全避免上面的异步结构。换句话说,它的语法(‘should do something’,function(done){});和$ httpBackend.flush()不能很好地在一起玩。 .flush()的目的是推送待处理的异步回调,然后返回。它就像一个大的完成包装你的所有异步回调。
所以如果我理解正确(它现在适用于我)正确的方法是删除done()处理器时使用$ httpBackend.flush():
it('does GET requests',function() { $httpBackend.expectGET('/some/random/url').respond('The response'); service.get('/some/random/url').then(function(result) { expect(result.data).toEqual('The response'); }); $httpBackend.flush(); });
如果添加console.log语句,您会发现所有的回调在flush()周期中始终发生:
it('does GET requests',function() { $httpBackend.expectGET('/some/random/url').respond('The response'); console.log("pre-get"); service.get('/some/random/url').then(function(result) { console.log("async callback begin"); expect(result.data).toEqual('The response'); console.log("async callback end"); }); console.log("pre-flush"); $httpBackend.flush(); console.log("post-flush"); });
然后输出将是:
pre-get
pre-flush
async callback begin
async callback end
post-flush
每次。如果你真的想看到它,抓住范围,看看范围。$$阶段
var scope; beforeEach(function(){ inject(function($rootScope){ scope = $rootScope; }); }); it('does GET requests',function() { $httpBackend.expectGET('/some/random/url').respond('The response'); console.log("pre-get "+scope.$$phase); service.get('/some/random/url').then(function(result) { console.log("async callback begin "+scope.$$phase); expect(result.data).toEqual('The response'); console.log("async callback end "+scope.$$phase); }); console.log("pre-flush "+scope.$$phase); $httpBackend.flush(); console.log("post-flush "+scope.$$phase); });
你会看到输出:
pre-get undefined
pre-flush undefined
async callback begin $digest
async callback end $digest
post-flush undefined