As a developer, I was running away from writing unit tests of UI. However, it is important to develop practice to write the UI unit tests. There are many reasons for that and we are not going to go in that direction, so let's come to the point.
In this blog, we are going to learn how to write unit test cases for AngularJS controllers with the help of Jasmine library.
Prerequisites:
Other points to consider:
I have created a plunk, which we are going to use as a reference.
In this blog, we are going to learn how to write unit test cases for AngularJS controllers with the help of Jasmine library.
Prerequisites:
- AngularJS
- Some details regarding why we write unit test cases would help
Other points to consider:
- For Jasmine 2.x, there are few changes in some methods.
For example, for Jasmine 1.3, you would write spyOn(mockObj, ‘method’).andReturn(someReturnVal)
The same thing for Jasmine 2.x, you would write as spyOn(mockObj, ‘method’).and.return(someReturnVal)
Also, there are some changes/enhancement in 2.x, but as of now, we will just focus on the basics. - You all might be aware that Angular 2 (or 4+) is going to use TypeScript; if you are going to write unit test cases for Angular 2 (4+) using Jasmine, there will be just change in the syntax of the test case. The concept would just remain the same. For example (given in https://docs.angularjs.org),
describe('sorting the list of users', function() {
it('sorts in descending order by default', function() {
var users = ['jack', 'igor', 'jeff'];
var sorted = sortUsers(users);
expect(sorted).toEqual(['jeff', 'jack', 'igor']);
});
});
The same thing you would write in TypeScript as per below.describe('sorting the list of users', () => {
it('sorts in descending order by default', () => {
var users = ['jack', 'igor', 'jeff'];
var sorted = sortUsers(users);
expect(sorted).toEqual(['jeff', 'jack', 'igor']);
});
});
In short, In short, the concepts you are going to learn in this blog are also going to be applicable for the latest version of Angular as well as Jasmine.
I have created a plunk, which we are going to use as a reference.
If you cannot see this embedded plunk properly, click on this link to open it in new browser window/tab.
Now let’s start understanding how to write unit test cases. Keep your eyes on myMathControllerSpec.js.
If you observe at bird's eye view, you can identify that the UTC file consist of.....
- one describe section/function call at root level
- beforeEach section(s)/call(s)
- there is an inject section/call within beforeEach where we get/create the instances of the dependencies
- it section/call where we write and execute individual test cases
You will also observe that we are...
- Initially loading the current and dependant external module
- Load/create external dependencies to instantiate the controller
- Inject the dependencies and create controller instance
- Prepare the data and set spies (check in the test case #2)
- Call the function and test the expected result
It’s better to provide examples than explaining the same in thousands of words!
So here I am going to provide you the quick references and examples for what kind of unit test cases you can write with Jasmine. All the references belong to the plunk I have created.Now check myMathController.js and its Spec file - specially test case #2. Below things you will see and learn there.
- How to set ‘spyOn’ for a service method and returning a fake result
- How to expect the service method to get called
- How to expect the service method to get called with specific arguments
- How to expect the result as a controller $scope property
- How to check if the method is called single or multiple times
- How to get the details about just the most recent call of a service
- How to reset the spy set on a method (setting isSpy = false)
- How to expect and test a function throwing exception/error.
- You’ll simply set spyOn a method and throw error in this way
spyOn(myMathSvc, 'divide').andThrow(new Error(errorMsg));
- You’ll simply set spyOn a method and throw error in this way
- How to test the controller if we are not using $scope level properties (using this inside controller)
- In this type of controller, we use this keyword extensively. You’ll find the example in myThisControllerSpec.js. Have a look at the controller before moving ahead!
- How to test $watch callback on a controller property.
- Many times we keep $watch on a controller property and do some operations when it changes. Example is explained in myHttpController and testing for the same is provided in related Spec file – test case #4.
- How to test $viewContentLoaded callback function
- In some cases, we want to call data load operation or any other thing once we are sure that the view is loaded into the DOM. As you know, $viewContentLoaded event is called when this happens. Example of it is given in myHttpController ($scope.getData()) and testing for the same is provided in related Spec file – test case #3.
- Here we need to load the controller in HTML markup template and compile it against the scope. i.e.
var viewTemplate = 'divStart ng-controller="myHttpController" divEnd'; //consider the appropriate tags in the above statement $compile(viewTemplate)(scope); scope.$digest();
- How to test an async service call – or – a service call returning promise.
- This is very well explained in test case #2 of myHttpController. Have a look at how getServerData is called within the controller first of all.
- Don’t miss to learn from the comment I have provided over there – then/finally part!!
I will be covering them next time. Till then, happy learning!
Comments
Post a Comment