Javascript 带有$http请求的AngularJS单元测试从不触发.then()回调
我试图在单独的json文件中使用模拟响应运行单元测试。当我使用$q返回在OpsService中手动解析的承诺时,测试是有效的,但当我试图将它们转换为实际的$http请求以返回实际的json文件时,它们不再有效 编辑:我尝试了Javascript 带有$http请求的AngularJS单元测试从不触发.then()回调,javascript,angularjs,json,karma-jasmine,Javascript,Angularjs,Json,Karma Jasmine,我试图在单独的json文件中使用模拟响应运行单元测试。当我使用$q返回在OpsService中手动解析的承诺时,测试是有效的,但当我试图将它们转换为实际的$http请求以返回实际的json文件时,它们不再有效 编辑:我尝试了$httpBackend.flush(),$rootScope.$apply(),和$rootScope.$digest(),但这些似乎都不能解决承诺 我的服务: OpsService.service('OpsService', function ($q, $http) {
$httpBackend.flush()
,$rootScope.$apply()
,和$rootScope.$digest()
,但这些似乎都不能解决承诺
我的服务:
OpsService.service('OpsService', function ($q, $http) {
this.get = {
bigTen : function () {
// var defer = $q.defer();
// defer.resolve({"data":{"alltime":125077,"record":{"date":"2016-07-19","count":825},"today":281}});
// return defer.promise;
return $http({
method: 'GET',
url: '/jsonMocks/api/big-ten.json'
}).then(function (response) {
console.log('bigTen data');
console.log(response);
return response;
}, function (error) {
console.log('ERROR');
console.log(error);
});
},
dashboardData : function () {
console.log('blahhhhh');
return $http({
method: 'GET',
url: '/jsonMocks/api/dashboard-data.json'
}).then(function (response) {
console.log('dasbhoard data');
console.log(response);
return response;
}, function (error) {
console.log('ERROR');
console.log(error);
});
}
};
return this;
});
我的控制器:
homeModule.controller('HomeController', function ($scope, OpsService) {
var ctrl = this;
ctrl.loading = {
topMetrics: true,
dashboardData: true
};
function init() {
ctrl.topMetricData();
ctrl.getDashboardData();
ctrl.initialized = true;
}
ctrl.topMetricData = function () {
ctrl.loading.topMetrics = true;
console.log('in topMetricData()');
return OpsService.get.bigTen().then(function (bigTen) {
console.log('bigTenControllerCallback');
ctrl.loading.topMetrics = false;
return bigTen;
});
};
ctrl.getDashboardData = function () {
ctrl.loading.dashboardData = true;
console.log('in getDashboardData()');
return OpsService.get.dashboardData().then(function (response) {
console.log('getDashboardDataController Callback');
ctrl.loading.dashboardData = false;
return dashboardData;
});
};
init();
});
我的测试:
describe('home section', function () {
beforeEach(module('ngMockE2E'));
beforeEach(module('templates-app'));
beforeEach(module('templates-common'));
beforeEach(module('LROps.home'));
var $rootScope, $scope, $httpBackend, createController, requestHandler;
beforeEach(inject(function($injector, _$rootScope_, _$controller_, _OpsService_) {
$rootScope = _$rootScope_;
$httpBackend = $injector.get('$httpBackend');
var bigTenJson = readJSON('jsonMocks/api/big-ten.json');
console.log(bigTenJson);
$httpBackend.when('GET', '/jsonMocks/api/big-ten.json')
.respond(200, { data: bigTenJson });
// .respond(200, { data: 'test1' });
var dashboardDataJson = readJSON('jsonMocks/api/dashboard-data.json');
console.log(dashboardDataJson);
$httpBackend.when('GET', '/jsonMocks/api/dashboard-data.json')
.respond(200, { data: dashboardDataJson });
// .respond(200, { data: 'test2' });
var $controller = _$controller_;
createController = function() {
$scope = $rootScope.$new();
return $controller('HomeController', {
$scope : $scope,
OpsService : _OpsService_
});
};
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should retrieve big ten data', inject(function () {
$httpBackend.expect('GET', '/jsonMocks/api/big-ten.json');
$httpBackend.expect('GET', '/jsonMocks/api/dashboard-data.json');
// Controller Setup
var ctrl = createController();
// Initialize
$rootScope.$apply();
$rootScope.$digest();
expect(ctrl.topMetrics.display.messages.count).toEqual(745);
}));
});
因此,我的console.log()没有一个在.then()回调中触发。如果我改回返回一个$q.defer().resolve(response).promise
对象,它似乎可以正常工作
注意:我使用karma read json来读取json文件,并在测试中做出相应的响应。据我所知,它们被正确读取,只是承诺没有得到解决,因此.then()回调可以执行。编辑:
查看,当方法不能一起工作时,expect
和。它们是设置后端的不同选项
expect
看起来它添加了一个调用将发生的预期,并为您提供一个.respond()调用结果,以给出响应内容
when
只允许您为特定响应设置响应,而无需实际说明您期望它
因此,在您的测试中,expect
调用会在您执行定义时覆盖,并且不会返回任何响应,因为您没有配置响应
所以,我认为你可以摆脱期望,在你的控制器后面放一个flush
,就像这样:
it('should retrieve big ten data', inject(function () {
// Controller Setup
var ctrl = createController();
$httpBackend.flush();
// Initialize
$rootScope.$apply();
$rootScope.$digest();
expect(ctrl.topMetrics.display.messages.count).toEqual(745);
}));
或者将每个
之前的
中的时的更改为预期时的,然后您可能不需要进行刷新编辑:
查看,当方法不能一起工作时,expect
和。它们是设置后端的不同选项
expect
看起来它添加了一个调用将发生的预期,并为您提供一个.respond()调用结果,以给出响应内容
when
只允许您为特定响应设置响应,而无需实际说明您期望它
因此,在您的测试中,expect
调用会在您执行定义时覆盖,并且不会返回任何响应,因为您没有配置响应
所以,我认为你可以摆脱期望,在你的控制器后面放一个flush
,就像这样:
it('should retrieve big ten data', inject(function () {
// Controller Setup
var ctrl = createController();
$httpBackend.flush();
// Initialize
$rootScope.$apply();
$rootScope.$digest();
expect(ctrl.topMetrics.display.messages.count).toEqual(745);
}));
或者将beforeach
中的when
s更改为expect
s,这样您可能就不需要flush了。首先,每个断言的请求都应该是模拟请求。请求应该用$httpBackend.flush()
刷新,它会触发摘要,$rootScope.$apply()
和$rootScope.$digest()
(它们彼此重复)不应该被调用
第二件事是它不应该在控制器规范中完成!控制器是一个独立的单元,依赖于一个服务,它应该与模拟服务隔离测试<代码>操作服务
是一个不同的单元
it('should retrieve big ten data', inject(function () {
$httpBackend.expect('GET', '/jsonMocks/api/big-ten.json').respond(200, ...);
$httpBackend.expect('GET', '/jsonMocks/api/dashboard-data.json').respond(200, ...);
OpsService.get.bigTen().then(function (result) {
expect(result)...
}, function (err) {
throw err;
});
OpsService.get.dashboardData()...
$httpBackend.flush();
}));
it('should test a controller', inject(function () {
var OpsServiceMock = { get: {
bigTen: jasmine.createSpy().and.returnValue(...),
dashboardData: jasmine.createSpy().and.returnValue(...)
} };
$scope = $rootScope.$new();
var ctrl = $controller('HomeController', {
$scope : $scope,
OpsService : OpsServiceMock
});
$rootScope.$digest();
expect(OpsServiceMock.get.bigTen).toHaveBeenCalled();
expect(OpsServiceMock.get.dashboardData).toHaveBeenCalled();
expect...
}));
首先,每个断言的请求都应该是模拟请求。请求应该用$httpBackend.flush()
刷新,它会触发摘要,$rootScope.$apply()
和$rootScope.$digest()
(它们彼此重复)不应该被调用
第二件事是它不应该在控制器规范中完成!控制器是一个独立的单元,依赖于一个服务,它应该与模拟服务隔离测试<代码>操作服务
是一个不同的单元
it('should retrieve big ten data', inject(function () {
$httpBackend.expect('GET', '/jsonMocks/api/big-ten.json').respond(200, ...);
$httpBackend.expect('GET', '/jsonMocks/api/dashboard-data.json').respond(200, ...);
OpsService.get.bigTen().then(function (result) {
expect(result)...
}, function (err) {
throw err;
});
OpsService.get.dashboardData()...
$httpBackend.flush();
}));
it('should test a controller', inject(function () {
var OpsServiceMock = { get: {
bigTen: jasmine.createSpy().and.returnValue(...),
dashboardData: jasmine.createSpy().and.returnValue(...)
} };
$scope = $rootScope.$new();
var ctrl = $controller('HomeController', {
$scope : $scope,
OpsService : OpsServiceMock
});
$rootScope.$digest();
expect(OpsServiceMock.get.bigTen).toHaveBeenCalled();
expect(OpsServiceMock.get.dashboardData).toHaveBeenCalled();
expect...
}));
啊,是的,我也试过了,上面说没有需要刷新的调用:“错误:没有等待刷新的请求!”我会更新问题。谢谢你的快速回复!嗯,这对我来说意味着没有尝试任何请求,这很奇怪。发出请求之前的console.logs是否显示?是的,除了.then()回调函数中的日志外,我看到了每个控制台日志。我甚至在$http()请求之前有一些触发,我也看到了这些,所以我知道它进入了我的服务函数,我想我的模拟响应中出现了一些古怪的事情?所以,我注释掉了我的expect('GET')函数,它没有抱怨意外的请求。然后,我注释掉了when('GET')函数,它开始抱怨意外的响应。很确定这意味着服务正在启动$http()调用,但我的模拟响应没有返回承诺?也许我必须用承诺来包装我的json?啊,是的,我也试过了,它说没有刷新的调用:“错误:没有等待刷新的请求!”我会更新问题。谢谢你的快速回复!嗯,这对我来说意味着没有尝试任何请求,这很奇怪。发出请求之前的console.logs是否显示?是的,除了.then()回调函数中的日志外,我看到了每个控制台日志。我甚至在$http()请求之前有一些触发,我也看到了这些,所以我知道它进入了我的服务函数,我想我的模拟响应中出现了一些古怪的事情?所以,我注释掉了我的expect('GET')函数,它没有抱怨意外的请求。然后,我注释掉了when('GET')函数,它开始抱怨意外的响应。很确定这意味着服务正在启动$http()调用,但我的模拟响应没有返回承诺?也许我必须用承诺来包装我的json?是的。在我的代码的完整版本中,我是console.log(ing)从该文件读取的json,它就在那里。如果找不到文件,readJSON()函数将抛出错误。是。在我的代码的完整版本中,我是console.log(ing)从该文件中读取的json,这都是t