Я пытаюсь разработать лучший способ для unit test успешных и обратных вызовов ошибок в контроллерах. Я могу издеваться над методами обслуживания, пока контроллер использует только функции $q по умолчанию, такие как "then" (см. Пример ниже). У меня возникла проблема, когда контроллер отвечает обещанию "успех" или "ошибка". (Извините, если моя терминология неверна).
Вот пример controller\service
var myControllers = angular.module('myControllers');
myControllers.controller('SimpleController', ['$scope', 'myService',
function ($scope, myService) {
var id = 1;
$scope.loadData = function () {
myService.get(id).then(function (response) {
$scope.data = response.data;
});
};
$scope.loadData2 = function () {
myService.get(id).success(function (response) {
$scope.data = response.data;
}).error(function(response) {
$scope.error = 'ERROR';
});
};
}]);
cocoApp.service('myService', [
'$http', function($http) {
function get(id) {
return $http.get('/api/' + id);
}
}
]);
У меня есть следующий тест
'use strict';
describe('SimpleControllerTests', function () {
var scope;
var controller;
var getResponse = { data: 'this is a mocked response' };
beforeEach(angular.mock.module('myApp'));
beforeEach(angular.mock.inject(function($q, $controller, $rootScope, $routeParams){
scope = $rootScope;
var myServiceMock = {
get: function() {}
};
// setup a promise for the get
var getDeferred = $q.defer();
getDeferred.resolve(getResponse);
spyOn(myServiceMock, 'get').andReturn(getDeferred.promise);
controller = $controller('SimpleController', { $scope: scope, myService: myServiceMock });
}));
it('this tests works', function() {
scope.loadData();
expect(scope.data).toEqual(getResponse.data);
});
it('this doesnt work', function () {
scope.loadData2();
expect(scope.data).toEqual(getResponse.data);
});
});
Первый тест проходит, а второй терпит неудачу с ошибкой "TypeError: Object не поддерживает свойство или метод" успех ". Я получаю, что в этом случае getDeferred.promise не имеет функции успеха. Хорошо, вот вопрос, что это отличный способ написать этот тест, чтобы я мог проверить условия "успеха", "ошибки" и "затем" издевательства?
Я начинаю думать, что мне следует избегать использования success() и error() в моих контроллерах...
ИЗМЕНИТЬ
Итак, подумав об этом еще немного, и благодаря подробному ответу ниже, , я пришел к выводу, что обработка успешных и обратных вызовов ошибок в контроллере плохая. Как упоминает HackedByChinese ниже успех\ошибка - это синтаксический сахар, который добавляется через $http. Таким образом, на самом деле, пытаясь справиться с успехом \error, я разрешаю утечкам $http в мой контроллер, чего я пытаюсь избежать, обернув $http-вызовы в службе. Подход, который я собираюсь сделать, - это изменить контроллер, чтобы не использовать success\error:
myControllers.controller('SimpleController', ['$scope', 'myService',
function ($scope, myService) {
var id = 1;
$scope.loadData = function () {
myService.get(id).then(function (response) {
$scope.data = response.data;
}, function (response) {
$scope.error = 'ERROR';
});
};
}]);
Таким образом, я могу проверить условия ошибки \success, вызвав resol() и reject() на отложенном объекте:
'use strict';
describe('SimpleControllerTests', function () {
var scope;
var controller;
var getResponse = { data: 'this is a mocked response' };
var getDeferred;
var myServiceMock;
//mock Application to allow us to inject our own dependencies
beforeEach(angular.mock.module('myApp'));
//mock the controller for the same reason and include $rootScope and $controller
beforeEach(angular.mock.inject(function($q, $controller, $rootScope, $routeParams) {
scope = $rootScope;
myServiceMock = {
get: function() {}
};
// setup a promise for the get
getDeferred = $q.defer();
spyOn(myServiceMock, 'get').andReturn(getDeferred.promise);
controller = $controller('SimpleController', { $scope: scope, myService: myServiceMock });
}));
it('should set some data on the scope when successful', function () {
getDeferred.resolve(getResponse);
scope.loadData();
scope.$apply();
expect(myServiceMock.get).toHaveBeenCalled();
expect(scope.data).toEqual(getResponse.data);
});
it('should do something else when unsuccessful', function () {
getDeferred.reject(getResponse);
scope.loadData();
scope.$apply();
expect(myServiceMock.get).toHaveBeenCalled();
expect(scope.error).toEqual('ERROR');
});
});