我有一个保存资源的控制器。我无法告诉他如何访问"在promise解析后执行的代码部分。我需要对我的测试或控制器进行哪些更改才能使其正常工作?这是代码。
控制器:
'use strict';
/**
* @ngdoc function
* @name lunchHubApp.controller:AnnouncementsCtrl
* @description
* # AnnouncementsCtrl
* Controller of the lunchHubApp
*/
angular.module('lunchHubApp')
.controller('AnnouncementsCtrl', ['$scope', 'Announcement', function ($scope, Announcement) {
$scope.announcements = [];
$scope.save = function() {
// This next line is the part I'm finding hard to test.
new Announcement($scope.announcement).create().then(function(announcement) {
$scope.foo = 'bar'
});
};
}]);
测试:
'use strict';
describe('AnnouncementsCtrl', function() {
beforeEach(function() {
module('lunchHubApp', 'ng-token-auth')
});
it('sets scope.announcements to an empty array', inject(function($controller, $rootScope) {
var scope = $rootScope.$new(),
ctrl = $controller('AnnouncementsCtrl', { $scope: scope });
expect(scope.announcements).toEqual([]);
}));
describe('save', function() {
it('works', inject(function($controller, $rootScope, _$httpBackend_) {
var $httpBackend = _$httpBackend_;
var scope = $rootScope.$new(),
ctrl = $controller('AnnouncementsCtrl', { $scope: scope });
expect(scope.announcements.length).toBe(0);
var announcement = {
restaurantName: 'Bangkok Taste',
userId: 1
};
scope.announcement = announcement;
$httpBackend.expect('POST', '/api/announcements').respond(200, announcement);
scope.save();
scope.$digest();
expect(scope.foo).toEqual('bar');
}));
});
});
更新:这就是我最终修改控制器测试的方式。以下通过并已从原始版本重构。
'use strict';
describe('AnnouncementsCtrl', function() {
var $httpBackend,
announcement,
scope,
ctrl;
beforeEach(function() {
module('lunchHubApp');
inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
scope = $injector.get('$rootScope').$new();
ctrl = $injector.get('$controller')('AnnouncementsCtrl', { $scope: scope });
announcement = { restaurantName: 'Bangkok Taste' };
scope.announcement = { restaurantName: 'Jason\'s Pizza' };
$httpBackend.expect('GET', '/api/announcements').respond([announcement]);
});
});
it('sets scope.announcements to an empty array', function() {
expect(scope.announcements).toEqual([]);
});
it('grabs a list of announcements', function() {
expect(scope.announcements.length).toBe(0);
$httpBackend.flush();
expect(scope.announcements.length).toBe(1);
});
describe('save', function() {
beforeEach(function() {
$httpBackend.expect('POST', '/api/announcements').respond(200, { restaurantName: 'Foo' });
scope.save();
$httpBackend.flush();
});
it('adds an announcement', function() {
expect(scope.announcements.length).toBe(2);
});
it('clears the restaurant name', function() {
expect(scope.announcement.restaurantName).toEqual('');
});
});
});
答案 0 :(得分:1)
我认为你所做的事情很好。由于 Angular资源是以 restful方式使用$http服务的工厂,因此您应该使用$httpBackend的expect
就像你一样。
但是,您要错过的一件事是您需要确保您的承诺得到解决。但在某些情况下,写异步测试可能会很棘手。为此,您必须使用 $ httpBackend 的 flush() 方法强制您的测试同步。
在同花顺之后,您可以正常使用expect
。此外,您可能需要在expectPOST
声明之前移动$rootScope.$new()
。
你可以接受这样的改变,我不认为$digest()
是必要的:
$httpBackend.expect('POST', '/api/announcements').respond(200, announcement);
scope.save();
$httpBackend.flush();
expect(scope.foo).toEqual('bar');
答案 1 :(得分:1)
您开始撰写的测试似乎不只是测试AnnouncementsCtrl
,还测试Announcements
服务/工厂。在这种情况下的迹象是
Announcements
服务/工厂/没有抄袭任何方法。AnnouncementsCtrl
中没有关于发出http请求的代码,但您在测试中使用$httpBackend.expect(...
。AnnouncementsCtrl
的测试成功/失败将成功或失败,具体取决于Announcements
服务/工厂中的代码。这违背了通常用于单元测试的内容:单独测试每个组件。保持这个答案的焦点在测试成功回调传递给create
返回的promise的then方法,我的建议是模拟Announcements
服务/工厂,所以它的create方法返回一个promise你可以在测试中控制。这个模拟的形式如下:
var MockAnnouncement = null;
var deferred = null;
beforeEach(module(function($provide) {
MockAnnouncement = function MockAnnouncement() {
this.create = function() {
return deferred.promise;
};
};
$provide.value('Announcement', MockAnnouncement);
}));
然后,您必须确保在每次测试之前创建延迟对象:
beforeEach(inject(function($rootScope, $controller, $q) {
$scope = $rootScope.$new();
deferred = $q.defer(); // Used in MockAnnouncement
ctrl = $controller('AnnouncementsCtrl', {
$scope: $scope
});
}));
然后在测试中解析此延迟对象:
it('calls create and on success sets $scope.foo="bar"', function() {
$scope.save();
deferred.resolve();
$scope.$apply();
expect($scope.foo).toBe('bar');
});
稍微扩展一下,测试控制器的一些其他行为,可以在http://plnkr.co/edit/v1bCfmSPmmjBoq3pfDsk
看到