How the Unit Tests transform your Angular's applications.

Best Practices for Implementing Unit Tests in Angular

Unit testing is an essential part of software development, along with End-to-End (E2E) and Integration Testing. It plays a key role in ensuring our application's quality. For software developers, this can be one of the most challenging aspects of Angular. It involves deeply simulating how Angular operates, grasping the workings of Dependency Injection, the Lifecycles of Angular, and how to simulate (mock) services. Initially, understanding and crafting a good unit test can be quite difficult.

Testing Pyramid

Testing Pyramid

The objective of the testing pyramid is to optimize the quantity of rapid and cost-effective tests (unit tests) while reducing the frequency of slower and more costly tests (E2E tests). This approach not only enhances the efficiency of testing but also facilitates prompt identification of issues. In essence, the testing pyramid serves as a strategic framework for effectively and efficiently allocating testing resources, thereby ensuring the software's quality in a scalable manner.

But, Why is Unit Testing important?

  • Find errors early: Unit tests let you spot mistakes in your code as you create it, so it's easier to fix them before users are affected.

  • Make better code: Writing unit tests makes you think about how your code works and helps ensure it's well-made.

  • Refactor safely: Unit tests give you confidence that you can change your code without causing problems.

  • Boost code coverage: Code coverage is the percentage of code that unit tests run. High code coverage shows that your code is well-tested (And that's where the importance of doing a good Unit Test lies).

What tools do you have to do unit tests in Angular?

Angular has built-in tools for unit tests. The main ones are:

  • Karma: A test runner that runs unit tests in the browser.

  • Jasmine: A framework for writing unit tests.

  • TestBed: A module that helps you set up a testing environment for your component.

  • Jest: A framework for writing tests in the browser and can be used in replace of Karma.

What makes a test a good Unit Test?

Some recommended practices for conducting a Unit Test include:

  • Arrange, Act, Assert (AAA)

    • Arrange: This is the setup so that our test has everything it needs to function.

    • Act: Execute the action

    • Assert: Verify the result of the Act.

  • Isolate the component to be tested

  • For components that depend on services for their behavior, use “Test Doubles” (mocks, stubs, doubles).

  • Use spies to verify the behavior of methods or functions.

  • Always use Mock data. This makes the tests predictable.

  • Use a good name for the Unit Test.

  • Test the expected interactions: Click on our buttons, don't call methods directly

it('should emit form value when the user clicks the button and form is valid', async () => {
      const expectedEmittedQueryValue = 'test';
      component.form.setValue({ query: expectedEmittedQueryValue });

      // Spies
      const submitSpy = jest.spyOn(component, 'submitForm');
      const outputSpy = jest.spyOn(component.query, 'emit');

      // Find the button
      const button = de.nativeElement.querySelector(

      // Always check the null

      // Simulate the click of the user at the button;

  • Find elements with data-testId, not with CSS classes.
it('form should be reset when click clear icon', async () => {
        // Add something to the form
        component.form.setValue({ query: 'test' });

        await fixture.whenStable();

        // Use the data-testId not the class name of the element
        const clearIcon = de.nativeElement.querySelector(
        // Check the null

        // Act
        jest.spyOn(component, 'resetForm'); // Spi the method; // Simulate the click the element

        // Assert
  • Test all possible code paths (both true and false)
it('should show loading button when input is loading `true`', () => {
      // arrange
      const button = fixture.debugElement.query(

      // checking the false
      fixture.componentRef.setInput('isLoading', false);

      // assert

      // checking the true
      fixture.componentRef.setInput('isLoading', true);

      // assert
  • Mock a service used in a component to verify the message displayed in the component
describe('UserComponent', () => {
  let component: UserComponent;
  let fixture: ComponentFixture<UserComponent>;
  let userServiceMock: Partial<UserService>;

  beforeEach(async () => {
    // create a mock of the service
    userServiceMock = {
      isLoggedIn: jest.fn(),

    await TestBed.configureTestingModule({
      declarations: [UserComponent],

      // Replace the UserService with the mock
      providers: [{ provide: UserService, useValue: userServiceMock }],

    fixture = TestBed.createComponent(UserComponent);
    component = fixture.componentInstance;

  it('should show "Logged In" if the user is logged in', () => {
    // manipulate the value of isLoggedIn to return true
    expect(component.message).toBe('Logged In');

  it('should show "Not Logged In" if the user is not logged in', () => {
    // manipulate the value of isLoggedIn to return false
    expect(component.message).toBe('Not Logged In');

What other tools do I use for Unit Test

  1. Spectator: Simplifies Angular testing by removing repetitive tasks, making unit tests clear and efficient. It enables testing components, directives, services, and more without needing deep knowledge of TestBed, ComponentFixture, and DebugElement APIs. Features include simple DOM querying, event triggering, routing and HTTP testing support, auto-mocking providers, and Jest compatibility.

  2. NgMock: This is a library for Angular that simplifies the creation of mocks in tests, allowing the simulation of components, directives, pipes, services, modules, and tokens. It makes configuring TestBed easier, reduces repetitive code in tests, and offers a simple interface to access declarations. Compatible with various versions of Angular, NgMocks supports both Jasmine and Jest, helping to create a more efficient and less tedious testing environment.


In conclusion, unit testing is crucial for creating robust and reliable Angular applications. It allows developers to catch errors early, enhance code quality, ensure safe refactoring, and achieve high code coverage. With Angular's tools like Karma, Jasmine, TestBed, and optionally Jest, developers can follow best practices such as Arrange, Act, Assert (AAA), component isolation, using test doubles, and testing all code paths. These strategies lead to functional, maintainable, and scalable applications, improving software quality and the development process.

Did you find this article valuable?

Support Arcadio Quintero by becoming a sponsor. Any amount is appreciated!