I am struggling to understand how to unit test a simple app AngularJS with Jasmine and Karma. I have tried googling but haven't made any progress with my own code. Specially around mocking and injecting of a factory service that depends on the built-in $http service.
Also, is good practice to unit test both the controller and factory service or one of them is sufficient.
I have uploaded the code to plunkr and would appreciate any help
https://plnkr.co/edit/WBpJ7gUZrNm8LwnCOsnR
factory.main.js
angular.module('hwApp').factory('mainFactory', ['$http', function($http){
return {
getData: function(){
return $http.get('https://jsonplaceholder.typicode.com/posts/1');
}
}
}]);
controller.main.js
angular.module('hwApp').controller('MainCtrl', ['mainFactory', function(mainFactory){
vm = this;
mainFactory.getData().then(function(res){
vm.httpData = res.data;
})
}]);
index.html
<!DOCTYPE html>
<html ng-app="hwApp">
<head>
<script data-require="[email protected]" data-semver="1.5.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script src="factory.main.js"></script>
<script src="controller.main.js"></script>
</head>
<body ng-controller="MainCtrl as vm">
<h1>{{vm.httpData.title}}</h1>
</body>
</html>
Typically, you would unit test the controller and the service separately. Pluralsight has a great course on using ngMock to do unit tests for controllers and services. I recommend finding some tutorials that can walk you through it, but I can supply you with an example of what you're looking for in testing your factory.
describe("your backend service", function () {
var dataWeWantToGet = [ "put", "your", "data", "here" ];
var mainFactory;
var $httpBackend;
beforeEach(angular.mock.module("hwApp"));
beforeEach(inject(function (_mainFactory_, _$httpBackend_) {
mainFactory = _mainFactory_;
$httpBackend = _$httpBackend_;
}));
it("should return movie search data from the title", function() {
var response = [];
$httpBackend.when('GET', 'https://jsonplaceholder.typicode.com/posts/1')
.respond(200, dataWeWantToGet);
mainFactory.getData()
.then(function onSuccess(data) {
response = data;
});
$httpBackend.flush();
expect(response.data).toEqual(dataWeWantToGet);
}); // end it
}); // end describe
In this example we're mocking both the backend and the code that would happen in the controller. This kind of isolation is necessary to prove that your factory works independently of your controller.
When testing your controller, you want to achieve similar isolation, but I think it is debatable whether you need to bother with testing just the functionality of your service through the controller. You practically did just that. To unit test just that part of your controller you'd have to inject the service that you've just tested and use it in the way that you just tested in your factory's unit tests.
This is where the question of how much to test and what begins to be controversial? Personally, I don't know if I would bother testing the service as it is used in the controller. I would test if those things affected by it update correctly. In Angular that's usually the greater challenge. I'd love to hear from others about it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With