Unit Testing in Angular 15 for Developers

Unit Testing in Angular 15 for Developers

Unit testing is something that is important for our application. Why??

Unit testing is something that is important for our application. Why??

Because it increases the quality of our application, test and determines if it works as intended, and helps us detect bugs early in the development cycle, today we are about to cover Unit testing in general as well as in angular from basics.

Let’s dive in,

Here are a few types of automated testing:

  • Unit Testing

  • E2E Testing

  • Integration Testing

Unit testing is focused on testing individual units or a component of an application in isolation from the rest of the application. The purpose of unit testing is to verify that each unit of code is working correctly and as expected. It involves writing and running automated test cases that check the functionality of a small piece of code, such as a function or a class.

E2E testing also known as end-to-end testing involves testing the entire application by automating the web browser to test a live running application with front end application, web server, and database. With E2E testing, the entire application can be validated

Integration testing is defined as testing more than one unit but less than a complete application. It involves checking whether one part of the application works with another part. It typically involves testing how individual units of code work together in various combinations to ensure that they integrate and function as expected.

There is also, Functional testing involves checking whether the application meets the specified requirements. It typically involves testing the application’s inputs and outputs to ensure that they meet the desired specifications and that the application behaves as expected.

Different types of Unit Testing:

  • Isolated UT

  • Shallow UT

  • Deep Integration Testing

Isolated unit tests: Involves basic tests that isolate the testing of a single unit of code such as a class or function free of dependencies. It uses mock objects to simulate the behaviour of other components that the unit interacts with, to ensure that the unit functions correctly.

Shallow unit tests: Involves testing one or more components or services that depend on each other.

Deep integration tests: It can be a bit complex, it tests one or more components or services that depend on each other and includes nested components.Used to test multiple components that have child components. It verifies that the unit integrates correctly with all of its dependencies and works as expected.

During unit testing, components often have dependencies that may be bulky like API calls, database interaction etc. We don’t want to use it in unit testing components. To address this, mocking can be used. Mocking is a powerful technique for isolating units of code and testing them in isolation from their dependencies. By using mocks, developers can write unit tests that are fast and reliable, and that focus on the behaviour of the code being tested rather than the behaviour of external dependencies.

There are different types of mock objects:

Dummies: These are dummy classes or objects that replace actual objects in the unit test.

Stubs: These are classes that take control and simulate the behaviour of dependencies.

Spies: These are objects that record information about how a dependency is used during the test. They can be used to verify that certain methods are called the expected number of times or with the expected parameters.

Till now we discussed unit testing in general, now let’s talk about unit testing in Angular.

When we create an Angular project using the Angular CLI, it automatically installs all the necessary utilities for testing. This includes the Karma test runner and the Jasmine testing framework, as well as other dependencies.

Jasmine is a popular JavaScript testing library that provides a clean syntax for writing tests, as well as powerful features such as spies and matchers, which allow you to track function calls and arguments. Jasmine is often used for testing Angular applications because of its ease of use and powerful features.

Matchers are a key feature of the Jasmine testing framework that allows you to test whether a value or object meets certain expectations. Jasmine provides a rich set of matchers that you can use to test various aspects of your code. To use a matcher, call the expect function with the value that you want to test, and then chain it with the matcher that you want to use.

Some examples of matchers that Jasmine provides include:

  • expect(x).toBe(y): checks whether x is equal to y using the === operator.

  • expect(x).toEqual(y): checks whether x is deeply equal to y, which means that all of their properties and values are the same.

  • expect(x).toBeDefined(): checks whether x is defined, which means that it is not undefined.

  • expect(x).toBeNull(): checks whether x is null.

  • expect(x).toBeTruthy(): checks whether x is truthy, which means that it is not false, 0, null, undefined, or an empty string or array.

  • expect(x).toBeFalsy(): checks whether x is falsy, which means that it is false, 0, null, undefined, or an empty string or array.

  • expect(x).toContain(y): checks whether x contains y, which can be a string, array, or object property.

  • expect(x).toBeGreaterThan(y): checks whether x is greater than y.

  • expect(x).toBeLessThan(y): checks whether x is less than y.

expect(2+3).toEqual(5);

If these built-in matchers don’t fit your requirement, Jasmine also allows you to define custom matchers, for a specific condition that is not covered by the built-in matchers using "jasmine.addMatchers()"

// Define a custom matcher using jasmine.addMatchers()
beforeEach(function() {
  jasmine.addMatchers({
    toBeDivisibleByTwo: function() {
      return {
        compare: function(actual, expected) {
          var result = {};
          result.pass = actual % 2 === 0;
          if (result.pass) {
            result.message = actual + ' is divisible by 2';
          } else {
            result.message = actual + ' is not divisible by 2';
          }
          return result;
        }
      };
    }
  });
});

// Use the custom matcher in a test case
it('should test whether a number is divisible by 2', function() {
  expect(10).toBeDivisibleByTwo();
});

"describe" and "it" functions are used to define test suites and test cases.

describe function is used to group related test cases together. It takes two arguments: a string that describes the group of tests, and a callback function that contains the actual tests.

describe('Test Suite', function() {
  // tests go here
});

it function is used to define a single test case. It takes two arguments: a string that describes what the test is checking, and a callback function that contains the actual test code.

it('should return true when given an even number', function() {
  expect(isEven(2)).toBe(true);
});

disable or focus a test by using the 'x' or 'f' prefix, respectively, before the describe or it function. A disabled test will be skipped when the tests are run, while a focused test will be the only test that is run.

xdescribe('my disabled tests', function() {
  // tests that will be skipped go here
});

fdescribe('my focused tests', function() {
  // only these tests will be run
});

Jasmine provides hooks (beforeAll, beforeEach, afterAll, afterEach) for setting up and tearing down test fixtures. What it means is preparing the environment for running tests and cleaning up after the tests have been completed.

  • beforeAll function is called once before all of the tests in a test suite are run.

  • beforeEach function is called before each test case.

  • afterAll function is called once after all of the tests in a suite have been run

  • afterEach function is called after each test case.

describe('Test Suite 1', function() {
  let value;

  beforeEach(function() {
    value = 42;
  });

  it('should return the correct value', function() {
    expect(myFunction(value)).toEqual(84);
  });
});

Here before each test case value will be set to 42

Karma, on the other hand, is a test runner that can be used to execute tests written with Jasmine. It provides an easy way to run tests in multiple browsers and provides real-time feedback on test results, which makes the testing process more efficient.

Results of tests are shown in the terminal window in real-time, as well as in the browser window that Karma opens to run your tests.


AngularUnitTesting: a simple angular project to demonstrate angular unit testing from basics.

We have covered the fundamentals here, Next time will dive deep into writing test cases from scratch and exploring concepts like spies, TestBed, ComponentFixture and a lot more.