带有$ http请求的AngularJS单元测试从不触发.then()回调 [英] AngularJS unit test with $http request never fires .then() callbacks
问题描述
我正在尝试在单独的json文件中以模拟响应运行单元测试.当我使用$ q返回在OpsService中手动解析的promise时,这些测试正在工作,但是当我尝试将它们变成实际的$ http请求以返回实际的json文件时,它们不再起作用.
I'm trying to get unit tests running with mocked responses in separate json files. The tests were working when I used $q to return promises resolved manually in my OpsService, but when I tried to make them into actual $http requests to return the actual json files, they no longer worked.
我已经尝试过$httpBackend.flush()
,$rootScope.$apply()
和$rootScope.$digest()
,但是似乎没有一个能解决诺言.
edit: I've tried $httpBackend.flush()
, $rootScope.$apply()
, and $rootScope.$digest()
but none of those seem to resolve the promises.
我的服务:
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
对象,它似乎可以正常工作.
So, none of my console.log() are firing in the .then() callbacks. If I change back to returning a $q.defer().resolve(response).promise
object, it seems to work fine.
注意:我正在使用karma-read-json读取JSON文件并在测试中做出相应的响应.据我所知,它们已经被正确读取,只是承诺没有得到解决,因此.then()回调可以执行.
Note: I'm using karma-read-json to read the JSON files and respond accordingly in my tests. As far as I can tell, they're being read properly, it's just the promises aren't being resolved so the .then() callbacks can execute.
推荐答案
第一件事是,每个断言的请求都应为模拟请求.请求应使用$httpBackend.flush()
刷新,它会触发摘要,不应调用$rootScope.$apply()
和$rootScope.$digest()
(它们彼此重复).
The first thing is that each asserted request should be mocked request. The requests should be flushed with $httpBackend.flush()
, it triggers a digest, $rootScope.$apply()
and $rootScope.$digest()
(they duplicate each other) shouldn't be called.
第二件事是,它不应该在控制器规格中完成!控制器是一个依赖于服务的独立单元,应与模拟服务隔离对其进行测试. OpsService
是另一个单位.
The second thing is that it shouldn't be done in controller spec! Controller is a separate unit that depends on a service, it should be tested in isolation with mocked service. OpsService
is a different unit.
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...
}));
这篇关于带有$ http请求的AngularJS单元测试从不触发.then()回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!