Saturday, December 28, 2019

Unit Testing Angular 9 Application with Jasmine & Karma

Angular 9 Unit Testing tutorial with an example. We will learn how to write unit tests in for services and component in an Angular app using the Jasmine framework and karma (JavaScript Test Runner).
We always ship our final product after making thorough testing, It is a fundamental step in software development, and it can be done via various testing methods.
Unit Testing Angular 9 Application

There are many methods to test our code, such as automated testing, manual testing, performance testing, automated unit testing. These testing methods are chosen as per the testing requirement of an application.
There are 3 types of tests:

  1. Unit tests
  2. Integration tests
  3. End-to-End (e2e) tests

Angular 9 Unit Testing Example

A unit test is the process of examining the specific part of the application and make sure it is working correctly and most importantly unit tests are written by developers.
Jasmine provides several valuable functions to write tests. Here are the main Jasmine methods:

  • it(): Declaration of a particular test
  • describe(): It’s a suite of tests
  • expect(): Expect some value in true form
Writing tests with Jasmine and Karma is very easy, so, we will create a basic Angular application, then create a simple Angular component and service. Then, we will write some test cases for Angular component, and also write unit test a service with HttpTestingController.

Let’s get started testing an Angular component with the Jasmine test framework.
Karma in Angular 8/9
Karma is a test runner tool, it creates a browser instance, run tests to provide the expected results.

The benefit of using Karma is that it can be operated via command line and It refreshes the browser automatically whenever we make even minor changes in our app.
Configure Development Environment
To get along with this tutorial you must have Node js and npm configured on your system. Skip this step, If you have already configured otherwise follow the below tutorial to set up Node and NPM on your device.
Also, you must have installed the latest version of Angular CLI on your system.
npm install -g @angular/cli@latest
If Node, NPM, and Angular CLI configured adequately, then go to the next step.
Setting Up Angular App
Next, install the Angular project by running the below command:
ng new ng-unit-test
Head over to the project folder by using the following command:
cd ng-unit-test
Start the app on the browser:
ng serve --open
Now, you can view your app on the browser on the following port: localhost:4200.
Angular Component Testing Example
An Angular component is a collection of HTML template and a TypeScript class. So, to test a component first, we need to create a component.
Let’s name it pizza and run the below command to create the component.
ng generate component pizza
Above command has created a pizza folder, and inside the pizza folder create a title variable and assign some value to it.
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-pizza',
  templateUrl: './pizza.component.html',
  styleUrls: ['./pizza.component.css']
})
export class PizzaComponent implements OnInit {
  title = "I love pizza!"
  constructor() { }
  ngOnInit() {
  }
}
You can see there is another file created pizza.component.spec.ts and this is a test file which is responsible for testing in Angular and testing file looks like this.
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { PizzaComponent } from './pizza.component';
describe('PizzaComponent', () => {
  let component: PizzaComponent;
  let fixture: ComponentFixture<PizzaComponent>;
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ PizzaComponent ]
    })
    .compileComponents();
  }));
  beforeEach(() => {
    fixture = TestBed.createComponent(PizzaComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });
  it('should create', () => {
    expect(component).toBeTruthy();
  });
});
Writing tests in Angular is easy, now we are going to write a simple test within the describe() function.
it(`should have a title 'I love pizza!'`, async(() => {
  fixture = TestBed.createComponent(PizzaComponent);
  component = fixture.debugElement.componentInstance;
  expect(component.title).toEqual('I love pizza!');
}));
You need to use the ng test command to start testing an Angular component.
ng test
Above command built the app in watch mode and launched the karma.
The ng test command opened the watch mode in karma.
We added some content in the pizza component. Then we created the pizza component instance to verify its properties and functions inside of it for testing purpose.
Now, as you can see in the screenshot 5 specs and 0 failures, this means we passed the test for pizza as well as for AppComponent’s properties.
The fixture creates a wrapper around a component instance, The fixture TestBed.createComponent() method allows accessing the component and its template.

Unit Testing with Angular Service with HttpClient & HttpTestingController API
Next, we are going to look at how to unit test a service that handles the http requests in Angular.

Run the following command to create service inside the shared folder:
ng g s shared/post
We are using free REST API from JSONPlaceholder, a big thanks to them for providing such a beautiful collection of REST APIs.

After running the above command, we have got the following files:
app/shared/post.service.spec.ts
app/shared/post.service.ts
Next, import and register the PostService in app.module.ts file, also import and register HttpClientModule in the main app module file.

// app.module.ts

import { PostService } from './shared/post.service';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
  declarations: [...],
  imports: [
    HttpClientModule
  ],
  providers: [PostService],
  bootstrap: [...]
})
export class AppModule { }
Add the following code in the post.service.ts file, The api is called via getPosts() method and returns post list Observable and we subscribe to it.

// shared/post.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
export interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}
@Injectable({
  providedIn: 'root'
})
export class PostService {
  REST_API: string = 'https://jsonplaceholder.typicode.com/posts';
  constructor(private http: HttpClient) { }
  getPosts(): Observable<Post[]> {
    return this.http.get<Post[]>(`${this.REST_API}`)
  }
}
HttpTestingController service are beneficial in mocking the HTTP requests, and this process can not be followed without taking the help of HttpClientTestingModule.

In this Angular 9 tutorial, we are going to write a unit test for mocking the HTTP GET request by taking the help of the HttpTestingController service.

Add the following code in the shared/post.service.spec.ts file.

import { TestBed, async, inject } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { PostService } from './post.service';
describe('PostService', () => {
  let postService: PostService;
  let httpMock: HttpTestingController;
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule,
      ],
      providers: [
        PostService
      ],
    });
    postService = TestBed.get(PostService);
    httpMock = TestBed.get(HttpTestingController);
  });
  it(`should fetch posts as an Observable`, async(inject([HttpTestingController, PostService],
    (httpClient: HttpTestingController, postService: PostService) => {
      const postItem = [
        {
          "userId": 1,
          "id": 1,
          "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
          "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
        },
        {
          "userId": 1,
          "id": 2,
          "title": "qui est esse",
          "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
        },
        {
          "userId": 1,
          "id": 3,
          "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
          "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
        }
      ];

      postService.getPosts()
        .subscribe((posts: any) => {
          expect(posts.length).toBe(3);
        });
      let req = httpMock.expectOne('https://jsonplaceholder.typicode.com/posts');
      expect(req.request.method).toBe("GET");
      req.flush(postItem);
      httpMock.verify();
    })));
});
Import the HttpClientTestingModule and HttpTestingController and inject inside the TestBed method and also set up the Angular service, which we are going to unit test.

We also declared the Verify method via HttpTestingController, and it makes sure that there are no unmatched requests that are outstanding.

We defined the posts data in the postItem array and mocking the requests using the HttpTestingController. We subscribe to Observable returned from HTTP GET request and set up the expectations using the response.

Conclusion
Finally, Unit Testing Angular 9 Application with Jasmine & Karma tutorial with example is over. In this tutorial, we covered the following topics:

What types of tests?
What is unit testing?
How to unit test an Angular component?
How to test an Angular application from scratch?
How to unit test an Angular Service with HttpClient and HttpTestingController?
You can get the complete code of this tutorial on this Github repository.
Source : https://www.positronx.io/angular-unit-testing-application-with-jasmine-karma/