Testing

Introduction

Testing is an integral part of any Angular app. Apart from the peace of mind it brings, ensuring that your Angular app is tested gives you the following benefits:

  • Fewer bugs in production

  • Fewer code regressions

  • More maintainable code

  • Faster refactoring and upgrades

  • Less dead code

In this guide, you will get a closer look into the two types of testing that the Angular framework facilitates: unit and end-to-end testing. You will learn how you can use these two types of testing in order to take advantage of all of the benefits mentioned above.

Angular Unit Testing

Your Angular unit tests comprise the foundation of your app's testing story. The purpose of unit tests is to test your codebase function by function. Angular makes it easy for you to write unit tests for all of your Angular entities, from components to pipes and everything in between. By default, unit tests are generated for you when you use the Angular CLI's generate command to add a new entity. You can run ng generate component dog-breed to create a new component with a companion unit test along with it.

Let's say you have the following unit test for your DogBreedComponent:

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { DogBreedComponent } from './dog-breed.component';

describe('DogBreedComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        DogBreedComponent
      ],
    }).compileComponents();
  }));

  it('gets instantiated', () => {
    const fixture = TestBed.createComponent(DogBreedComponent);
    const comp = fixture.componentInstance;
    expect(comp).toBeTruthy();
  });

  it(`should contain a breed description`, () => {
    const description = 'This is a breed description',
              fixture = TestBed.createComponent(DogBreedComponent),
                 comp = fixture.componentInstance,
          baseElement = fixture.nativeElement;

    comp.description = description;
    fixture.detectChanges(); // Force our changes to run through Angular's change detection mechanim

    expect(baseElement.querySelector('.breed-description').textContent).toEqual(description);
  });

});

The above unit test file tests that the DogBreedComponent properly instantiates and displays the description within its template. Notice how you are able to test this component in isolation. The purpose of unit tests is to test each individual piece of functionality of your app. This buys you granular guarantees about your app and ensures that your code will be more maintainable and easier to refactor when the time comes.

Angular End-to-end Testing

Unlike unit tests, end-to-end tests focus on the big picture. The purpose of end-to-end tests is to ensure that your app functions properly from the perspective of the user. Whereas unit tests focus on testing individual pieces of your app in isolation, end-to-end tests run against a running instance of your app.

Normally, end-to-end tests are created for every page within your app. Here is an example of an end-to-end test suite for the dog breed app's home page:

import { browser, by, element } from 'protractor';

describe('Dog Breed Home Page', () => {
  it('should display the app title', () => {
    browser.get('/');

    expect(
        element(by.id('home-page-title').getText()
    ).toEqual('Welcome to Breed-topia!');
  });
});

See the difference between end-to-end tests and unit tests? The simple test suite above actually navigates to your app inside of a browser (typically headless Chrome) and tests that it looks and functions properly. Inside of end-to-end tests, it is your job to pretend to be the user as you navigate your app. End-to-end tests ensure that your app is free from regression bugs that might be introduced by new features or refactoring. They are integral in order to ensure your production build is functioning properly from the perspective of the user.

Conclusion

Through easy unit and end-to-end testing integration, Angular provides you many benefits. By writing unit tests, you can guard your code against regressions and provide a strong foundation that facilitates maintainability and ease of growth for your app. In the same way, end-to-end tests that run against your Angular app will ensure that your app functions as expected. This will ward off pesky bugs that can be introduced into production and will help facilitate the creation and/or extension of continuous integration and deployment pipelines for your app.

Testing is absolutely necessary to ensure your Angular app is maintainable. Check out the documentation for testing Angular apps for more information.

Last updated