Есть ли способ в AngularJs протестировать контроллеры с Сервисами и только mock\stub вещи, как $ http?

Я хотел бы протестировать мой контроллер через мои различные службы и обратно и только заглушить данные, которые возвращаются из вызовов в $ http.

Это подход, который я использую в С# с контейнерами IoC, где я только переопределяю зависимости, которые вы хотите заглушить для теста, и оставляйте все остальное как есть.

Есть ли способ сделать это в тестах AngularJs с Jasmine, чтобы я мог увеличить объем моих тестов, чтобы быть больше, чем один контроллер или услуга?

редактировать

Ниже приведен пример, чтобы прояснить подход, который я хочу использовать.

angular.module('app') .service('aController', [ 'servcieB', 'serviceC', function ($scope, serviceB, serviceC) { serviceC.doHttpSomething().then(function (result) { $scope.bSomething = serviceB.doSomething(result); }); } ]) .service('serviceB', function () { function doSomething(input) { return input + ' with something'; }; return { doSomething: doSomething } }) .service('serviceC', [ '$http', function (http) { function doHttpSomething() { return http.get('/something'); }; return { doHttpSomething: doHttpSomething } }]);

В надуманном коде выше я бы хотел написать один тест, который проверяет aController, serviceB и serviceC, а только mocks $ http. В макете $ http я хотел бы проверить, правильно ли вызвал serviceC, и затем сможет возвращать фиктивные данные, которые я могу проверить, правильно обработан службой B и правильно настроен на область действия aController, только проверяя, что ожидаемый результат на $ scope.bЧто-то правильно.

Я знаю, как тестировать каждый компонент отдельно по отдельности, но я хочу протестировать их все вместе, так как хочу написать меньше тестов и только хочу проверить правильность общего желаемого поведения. В С# этот подход позволяет мне изменить детали реализации, не переписывая кучу тестов, и, если возможно, я хотел бы выполнить тот же рабочий процесс.

Редактировать 2 - Рабочее решение ниже. Основываясь на отзывах Уильяма, я создал FiddleJs с рабочим примером, который моделирует мою ситуацию с наличием двух уровней сервисов (Domain и DAL) и только издевательством $ http в службах DAL.

Пример скрипки

/ / --- Js CODE --------------------------

angular.module('app', []) .controller('MainController', function ($scope, $log, BlogService) { $scope.username = 'Bret'; $scope.posts = []; BlogService.getPostByUserName($scope.username).then( function (response) { $log.debug('MainController.getPostByUserName reponse.length: ' + response.length); for (var i = 0; i < response.length; i++) { $scope.posts.push(response[i]); } });
}) .factory('BlogService', function ($q, $log, PostService, UserService) { function getPostByUserName(userName) { var deffered = $q.defer(); UserService.getUserByUserName(userName).then( function (user) { $log.debug('BlogService.getUserByUserName.then user:' + user + ' user.id: ' + user.id); PostService.getPosts().then( function (posts) { var postsByUser = []; for (var i = 0; i < posts.length; i++) { if (posts[i].userId === user.id) { postsByUser.push(posts[i]); } } deffered.resolve(postsByUser); }, function (error) { deffered.reject(error); }); }); return deffered.promise; }; return { getPostByUserName: getPostByUserName };
}) .factory('PostService', function ($http, $q) { function getPosts() { var deffered = $q.defer(); $http.get('http://jsonplaceholder.typicode.com/posts') .success(function (response) { deffered.resolve(response); }) .error(function (error) { deferred.reject(error); }); return deffered.promise; }; return { getPosts: getPosts };
}) .factory('UserService', function ($http, $q) { function getUserByUserName(userName) { var deffered = $q.defer(); $http.get('http://jsonplaceholder.typicode.com/users') .success(function (response) { var user; for (var i = 0; i < response.length; i++) { if (response[i].username === userName) { user = response[i]; break; } } deffered.resolve(user); }) .error(function (error) { deferred.reject(error); }); return deffered.promise; }; return { getUserByUserName: getUserByUserName };
});
//--- SPECS -------------------------
describe('app', function () { var endpointController; var dummyPosts = [ { "userId": 1, "id": 1, "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", "body": "quia et suscipit\nsuscipit recusandae ************ expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" }]; var dummyUsers = [ { "id": 1, "name": "Leanne Graham", "username": "Bret", "email": "[removed_email]", "address": { "street": "Kulas Light", "suite": "Apt. 556", "city": "Gwenborough", "zipcode": "92998-3874", "geo": { "lat": "-37.3159", "lng": "81.1496" } }, "phone": "1-770-736-8031 x56442", "website": "hildegard.org", "company": { "name": "Romaguera-Crona", "catchPhrase": "Multi-layered client-server neural-net", "bs": "harness real-time e-markets" } }, { "id": 2, "name": "Ervin Howell", "username": "Antonette", "email": "[removed_email]", "address": { "street": "Victor Plains", "suite": "Suite 879", "city": "Wisokyburgh", "zipcode": "90566-7771", "geo": { "lat": "-43.9509", "lng": "-34.4618" } }, "phone": "010-692-6593 x09125", "website": "anastasia.net", "company": { "name": "Deckow-Crist", "catchPhrase": "Proactive didactic contingency", "bs": "synergize scalable supply-chains" } }]; beforeEach(module('app')); it('should return posts by bret ', inject(function ($rootScope, $controller, $httpBackend) { var scope = $rootScope.$new(); $httpBackend.expectGET('http://jsonplaceholder.typicode.com/users') .respond(dummyUsers); $httpBackend.expectGET('http://jsonplaceholder.typicode.com/posts') .respond(dummyPosts); endpointController = $controller("MainController", { $scope: scope }); $httpBackend.flush(); expect(endpointController).not.toBeNull(); expect(scope.posts.length).toBe(1); }));
});

Чтобы привести пример в живую, вы можете использовать код представления ниже

/ / - Код HTML -----------------------

<div ng-app="app" ng-controller="MainController">{{ "Hellow " + message }} <div ng-repeat="post in posts">{{ post.title }}</div>
</div>
1 ответ

Проверьте $ httpBackend. Он позволяет указывать ответы для конкретных запросов.

Обновления

Используйте angular.mock.inject чтобы пройти обычный процесс инъекции. Вам необходимо явно подключить область действия:

var ctrl; //controller under test beforeEach(angular.mock.inject(function($rootScope, $controller, serviceB, serviceC) { scope = $rootScope.$new; ctrl = $controller('RatioBoxController', { $scope: scope, serviceB: serviceB, serviceC: serviceC, } ); }));

Вы можете использовать шпионы для проверки методов на serviceB или serviceC, или обычных проверок, предоставленных $httpBackend.

licensed under cc by-sa 3.0 with attribution.