我是Angular的新手,我正在测试一个运行API级别服务的Angular服务,该服务将大量调用包装到REST服务中.因为它正在处理HTTP请求,所以服务的两个部分都在使用promises,它似乎工作正常,但我无法对承诺的行为进行任何测试.
我的服务代码的相关部分(非常简化)如下所示:
angular.module('my.info') .service('myInfoService',function (infoApi,$q) { infoLoaded: false,allInfo: [],getInfo: function () { var defer = $q.defer(); if (infoLoaded) { defer.resolve(allInfo); } else { infoApi.getAllInfo().then(function (newInfo) { allInfo = newInfo; infoLoaded = true; defer.resolve(allInfo); }); } return defer.promise; } });
@H_301_10@当我设置我的模拟时,我有这样的事情:
describe("Info Service ",function() { var infoService,infoRequestApi,$q; beforeEach(module("my.info")); beforeEach(function() { module(function($provide) { infoRequestApi = { requestCount: 0,getAllInfo: function() { var defer = $q.defer(); this.requestCount++; defer.resolve( [ "info 1","info 2" ] ); return defer.promise; } }; $provide.value("infoApi",infoRequestApi); }); inject(function( _myInfoService_,_$q_ ) { infoService = _myInfoService_,$q = _$q_; }); }); it("should not fail in the middle of a test",function(done) { infoService.getInfo().then( function(infoResult) { // expectation checks. expect( true ).toBeTrue(); }).finally(done); }); });
@H_301_10@任何同步测试都没有通过,但是当我尝试运行这样的任何测试时,我收到一条消息:错误:超时 – 在jasmine.DEFAULT_TIMEOUT_INTERVAL指定的超时内没有调用异步回调.
看起来Angular.Mocks处理延迟结果的方式似乎导致它失败.当我逐步完成测试时,正确设置了模拟对象的延迟变量,但从不调用服务中的then语句.我哪里错了?
最佳答案
简答
原文链接:https://www.f2er.com/js/429072.html你必须开始一个消化周期.你可以用$rootScope.$apply()来做到这一点.
it("should not fail in the middle of a test",inject(function($rootScope) { var actualResult = null; infoService.getInfo() .then(function(infoResult) { actualResult = infoResult; }); $rootScope.$apply(); expect(actualResult).toEqual(["info 1","info 2"]); }));
@H_301_10@注意
我不会尝试按照你的方式创建一个假的infoRequestApi服务.您也应该注入该服务,并监视其功能.例如,像这样:
it("should not fail in the middle of a test",inject(function($rootScope,infoApi,$q) { var deferred = $q.defer(); spyOn(infoApi,'getAllInfo').and.returnValue(deferred.promise); var actualResult = null; var expectedResult = ["info 1","info 2"]; infoService.getInfo() .then(function(infoResult) { actualResult = infoResult; }); deferred.resolve(expectedResult); $rootScope.$apply(); expect(actualResult).toBe(expectedResult); }));
@H_301_10@重构
此外,您的代码可以简化一点(未经测试,但接近我期望看到的).
angular.module('my.info') .service('myInfoService',$q) { return { infoLoaded: false,getInfo: function () { var self = this; return this.infoLoaded ? $q.resolve(this.allInfo) : infoApi.getAllInfo().then(function (newInfo) { self.allInfo = newInfo; self.infoLoaded = true; }); } }; }); describe("Info Service ",function() { var infoService,$q,$rootScope; beforeEach(module("my.info")); beforeEach(inject(function( _myInfoService_,_$q_ _$rootScope_,_infoApi_) { infoService = _myInfoService_,$q = _$q_; $rootScope = _$rootScope_; infoApi = _infoApi_; }); it("should do something",function() { // update message var deferred = $q.defer(); spyOn(infoApi,'getAllInfo').and.returnValue(deferred.promise); var actualResult = null; var expectedResult = ["info 1","info 2"]; infoService.getInfo() .then(function(infoResult) { actualResult = infoResult; }); deferred.resolve(expectedResult); $rootScope.$apply(); expect(actualResult).toBe(expectedResult); }); });
@H_301_10@