icon

Unit Testing in Angular using Jasmine

Our Goals

  1. Brief Overview of Angular
  2. Testing in Angular
  3. Scope of Unit Testing in Angular
  4. How to do Unit Testing in Angular with available frameworks
  5. Mocking in Angular
  6. TDD & its importance
  7. Hands on

Brief Overview of Angular

What is Angular ??

Angular is an open source JavaScript MVW(Model View Whatever) framework maintained by Google and community of individuals.

It been quite number of years now exploring this framework & based on my handson let me put an unofficial definition around it.

Angular is javascript data binding framework where the data could be records, events etc.

How old is Angular??

It’s been quite number of years that Angular is competing right on the front in web development.

Angular 1.0 Oct 2010
Angular 2 September 2016
Angular 4 March 2017
Angular 5 November 2017

Testing in Angular:-

Yes it might sound strange unit testing js code. It’s been more than 15 years that JavaScript is playing around the browser, but in old days it was just an another scripting language but I think with the evolution of jQuery & such fantastic library JavaScript became the dominant part of the tech stack.

With Angular, React, Vue & other such framework has just won the race.  If I talk about any web application architecture, these days the architecture is standardising in the direction of SPA where on the server we will have APIs to serve data & all the binding, animations & processing will be done on the front end. So with such architecture it is equally imp that we make sure that our not only our server side but front end as well tested & enduring.

There are primarily 3 types of testing that can be achieved in Angular.

  • Unit Testing
  • Integration Testing
  • E2E Testing

I am restricting this article to unit testing & in the next blog, I will take you to other two types of testing.

Scope of Unit Testing in Angular

This is something really any team needs to think on. When should all these testing to be exercised. If you’re building some MVP or running high paced product development, my personal advice would be to keep this exercise on secondary.

Knowing things is one thing & implementing wisely is an another thing. Because writing test cases & achieving good degree of test outcome doesn’t assure you have written good quality code.

Be pragmatic & yes in long go automated testing is a boon for any application life.  This below graph (on googling) which I found will help you to understand the importance of it.

Manual vs Automation Testing Cost

 

 

How to do Unit Testing in Angular with available frameworks

We can test our Angular applications from scratch by writing and executing pure javascript functions. Creating instances of the relevant classes, calling functions and checking the actual versus expected result.

But since testing is such a common activity with javascript there are a number of testing libraries and frameworks we can use which reduce the amount of time it takes to write tests.

Jasmine is one of the most famous framework available. While working with Jasmine there are number of other libraries/packages that are required to achieve automated unit testing in angular

  • Jasmine Specs
  • Karma
  • Protactor
  • Angular Test Bed

Please don’t confuse these as parallel testing library, they come as suite..

Jasmine is an unit testing framework for JavaScript. You write all your test cases in Jasmine specs.

Karma is a tool which lets us spawn browsers and run jasmine unit tests inside of them all from the command line. Simply put, it’s your testing server.

Protractor is an end-to-end test framework for Angular applications. Protractor runs tests against your application running in a real browser.

Angular Test Bed (ATB) is a higher level Angular Only testing framework that allows us to easily test behaviours that depend on the Angular Framework.

Mocking in Angular

Discussion of any unit testing framework is incomplete without Mocking. So let me put some light on this very important aspect.

What is Mocking??

Mocking is primarily used in unit testing. An object under test may have dependencies on other (complex) objects. To isolate the behaviour of the object you want to test you replace the other objects by mocks that simulate the behavior of the real objects. This is useful if the real objects are impractical to incorporate into the unit test.

 

Testing with real instances of dependencies causes our test code to know about the inner workings of other classes resulting in tight coupling and brittle code.

The goal of Unit Tests  is to test pieces of code in isolation without needing to know about the inner workings of their dependencies.

We do this by creating Mocks; Later in this section, while hands-on will see how to do mocking?

 

TDD 

Before we get into action, let spend some time on understanding What is TDD??

Test-driven development (TDD) is an evolutionary approach to development which combines test-first development where you write a test before you write just enough production code to fulfill that test and refactoring. It is very suitable for unit testing.

Why TDD

Teams and developers should adopt TDD, and they should adopt it solely for the reduced number of defects. Also, it allows us to break the negative feedback loop and maintain a constant cost of change.

Having said this, I think we can realize the importance of the framework(Jasmine) in our development cycle.

 

Hands On

Lets get started & dig how does these looks like in real time development.

For this article, I am building a simple Calculator application in Angular 5 which has Addition, Subtraction, Multiplication & Division functions.

I am using Angular CLI for development.

1 . Go to your command prompt & run the below command to create a green field Angular application.

ng new <appName>

 

2. If the command run with success, you should see the following files in app folder.

3. Use ng serve command to run your application in your browser. This is how your application should look like

 

4. We’re going to create a Calculator Angular 5 component here for our basic calculation functions.

Calculator.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'app-calculator',
 templateUrl: './calculator.component.html',
 styleUrls: ['./calculator.component.css']
})
export class CalculatorComponent implements OnInit {

 constructor() { }

 ngOnInit() {
 }

 private num1 : number;
 private num2 : number;

 add(num1, num2):number{
 return (num1 + num2);
 }

 subtract(num1, num2) : number{
 return (num1 - num2);
 }

 multiply(num1, num2): number{
 return (num1 * num2);
 }

 divide(num1, num2):any {
 if(num2 < 0){
 return "Dr should not be 0";
 }
 else{
 return (num1/num2);
 }
 }
}

You will be writing all your jasmine test cases in .spec.js file.

Calculator.component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { CalculatorComponent } from './calculator.component';

//Suite
describe('CalculatorComponent', () => {
 //Arrange
 let component: CalculatorComponent;
 let fixture: ComponentFixture<CalculatorComponent>;

 //Setup
 beforeEach(async(() => {
 TestBed.configureTestingModule({
 declarations: [ CalculatorComponent ]
 })
 .compileComponents();
 }));
 
 //Setup
 beforeEach(() => {
 fixture = TestBed.createComponent(CalculatorComponent);
 component = fixture.componentInstance;
 fixture.detectChanges();
 });

 //Teardown
 afterEach(()=>{

 })
 //Specs //Act
 it('should create', () => {
 //Assert
 expect(component).toBeTruthy();
 });

 it('should return addition of two numbers', () => {
 expect(component.add(10,10)).toEqual(20);
 });

 it('should return difference of two numbers',() => {
 expect(component.subtract(10,10)).toEqual(0);
 });

});

In the above snippet, I have decorated some key concepts of the framework with comments
let me explain what are these.



Suite - The describe(string, function) function defines what we call a Test Suite, a collection of individual Test Specs.

Specs – The it(string, function) function defines an individual Test Spec, this contains one or more Test Expectations.

Arrange – Define & initialise all the variables required for the component.

Act – Call the function.

Assert –  The expect(actual) expression is what we call an Expectation. In conjunction with a Matcher it describes an expected piece of behaviour in the application.

Matcher – The matcher(expected) expression is what we call a Matcher. It does a boolean comparison with the expected value passed in vs. the actual value passed to the expect function, if they are false the spec fails.

Please find the list of all the matchers on the below link:-https://github.com/JamieMason/Jasmine-Matchers

Setup – Sometimes in order to test a feature we need to perform some setup. beforeAll(), beforeEach() are such functions to help you.

TearDown –  To perform some cleanup activities after we have finished testing. AfterAll(), AfterEach() are such functions to help you.

Running Jasmine Tests.

Now its time to run your test cases In order to run your test cases,please go to command prompt & run below command.

ng test

On running this command, a browser will be prompted with the following screen.

 

 

This screen shows that all your test cases has passed, in case any of the test cases fails or any exception you may see the screen as below.

 

Code Coverage

Code Coverage an imp aspect of the unit testing.  So how do I calculate code coverage in for angular entities?

Istanbul – a small utility is needed to generate the code coverage. This small utility gives a good overview of the code coverage.

npm install karma-jasmine-html-reporter karma-coverage-istanbul-reporter

This will generate a folder with name coverage under the root directory.

Next time, when you run ng test command it should have generate covergae reports.

Please click on the component link to view the inner details.

Mocking

Let’s create another component that will make use of some angular service. This service will communicate with back end API.

Create a basic Authentication service which has a method to check the user credentials against the back end API.

Create a Login Component which will make use of the above created service.

In such case, we will Mock the dependencies. There are a number of ways in which we can achieve mocking.

  • Mocking with Fake classes
  • Mocking by overriding functions
  • Mocking by using a real instance with Spy

 

Mocking with Fake classes

In this approach, we will create a fake class for the AuthService. Referring to the attached screenshot, if you observe I am not making any actual call to AuthService instead created a Fake class (line#7), for my unit testing the login component.

It may be possible in real, you may number of methods in your service but your component may be making use of one or two. In that case mocking a complete a class is an overhead. So in such case we would Mock by overriding function.

We would extend from the real Auth Service & override only the functions that are relevant to the component being under test.  This approach is called as Mocking by overriding functions.

Please obeserver on line#6, here we have overrided the single function that is used by our component instead of creating a complete fake class.

Apart from these 2 discussed approaches, a third approach also exists in Jasmine framework called Mocking by Spy.

A Spy  lets you take an existing class, function, object and mock it in such a way that you can control what gets returned from functions

 

Hope this blog helps to get started with Unit testing in Angular. Would love to hear your questions & suggestions.

Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *