How To Run Unit Testing In Angular

Svetloslav Novoselski / Monday, April 18, 2022

Most development teams will agree that unit testing in Angular is time-consuming and many will also agree that it is unnecessary — and will decide to skip it. Depending on the scale of your project and the programming skills of the people working on it, not testing your Angular app might be the right thing to do. But generally, unit testing is extremely valuable so as to avoid creating a poorly designed codebase that will result in much more costly debugging and code fixes later on. So, would you rather risk your code quality or would you prefer to understand the code you’re developing in advance, helping to find bugs in the code early in the development cycle? 

I say, don’t underestimate unit testing, especially when working on a large Angular app, big data, or data science projects.  

Here’s what this article will cover so you can understand why you should, at least, test that inputs are correct:

Try Ignite UI for Angular

The Broad Picture: What Is Unit Testing?

In software development, unit testing (also called isolated testing) is carried out to guarantee that your app is working the way it should, eliminating any bugs in separate units of the code in the development phase. A unit test can be run multiple times to verify the behavior of a particular unit of code for different sets of input.

It tackles issues like catching missing values, or questions like "Does the filter function narrow down values in the right way?," or more complex ones in data science apps such as “Do the function returns have shapes as expected?” and many others.

As To Why You Need Unit Testing, Here Is What I Think:

  • Performing unit testing enables you to detect and fix bugs immediately, thus avoiding unexpected outputs in a much later phase of the app development cycle when it will be more costly and time-consuming to rewrite the code.
  • Knowing what behavior to expect from a particular unit of the code, you can see what’s broken and can, therefore, update your code more easily.
  • Running unit tests gives you confidence on the quality of your code and helps you structure it in a better way.
  • You can test individual classes in isolation and the strengths of the coupling blocks in your app to see how they behave.
  • Unit testing allows refactoring, meaning you can modify the code in a bug-free way without changing how it behaves since you already know how everything works.
  • Since it is performed on isolated units of the code, any time you want to test a newly added feature or a file modification, you’re guaranteed that running unit testing won’t break the entire code.
  • Unit tests are super-fast and are capable of simulating all error conditions.
  • They cannot fail for accidental reasons like a network and service outage or data authentication errors.
  • Super useful in the so-called Extreme Programming methodology which essentially asks you to test everything that can possibly break.
  • If you want to learn about a functionality that a unit provides and see how to use it, you can use the unit tests to get basic understanding of the unit’s API.

What Is Unit Testing in Angular?

Unit testing in Angular is a process for testing individual units of code with the goal to identify issues like functions that misbehave, incorrect logic, and more as early as possible. And because Angular projects are modular by default, running unit tests on such apps feels a bit more intuitive as they let you examine your app’s functions in isolation.

Unlike other frameworks, Angular offers a great way to carry out unit tests of your models. Usually, developers do manual testing to check behaviors and see if their code is functional or not. However, in some cases, manually testing every single minor change takes more time compared to developing a unit test. But Angular delivers tools and test runners like Karma that do the unit testing for you.

Why You Should Test Angular Apps

Testing your Angular codebase function by function is the best way to improve code quality, have fewer bugs in production and less dead code, to reduce maintenance costs, and achieve faster refactoring and even upgrades without discrepancies breaking the entire code.

It may seem slow at first, but it pays off in the long run. Bugs are caught throughout development. The debugging process is improved. If a certain test fails, we can easily find what exactly isn’t working as expected. And because test driven development and unit testing in particular both sound a bit more challenging than they actually are, relying on new tools and best practices can really facilitate and automate the whole process.

How To Do Unit Testing in Angular & Test Angular Components

There are several things that a component can do and we must make sure that all of these behaviors are taken into account while writing tests for components:

  • They can render templates into the HTML DOM tree.
  • They can accept data from parent components using Inputs and emit data using Outputs.
  • They can interact to different types of events.
  • They can talk to services or stores.
  • They can bind data and allow the user to edit it.

In the next sections, I will demonstrate how to do unit testing in Angular and test components.

We will start testing Angular components, using Ignite UI for Angular. Here's what to do.

Set up TestBed

Angular provides TestBed for testing, which creates an environment where we can test components and services easily. It is configured like a normal Angular module and then all declared components are compiled. To save duplicated code in each test, we can use it in beforeEach function.

setting up testbed in angular unit testing code snippet

After components are compiled, we can create a component which is rendered in the HTML DOM. When a component is used in testing environment, it is not automatically re-rendered on updates. That's why we need to trigger it manually:

    fixture.detectChanges(); 

Testing the DOM

Most of the time, functions in the components are doing some logic which is reflecting the template. We can access the DOM tree using DebugElement and its methods query and queryAll:

  • query returns the first element that is matching a condition
  • queryAll returns a collection of matching elements

Using By.css() we can get elements by CSS selectors.

testing the dom in angular unit testing code screenshot

Triggering event handlers

Imagine we have a function which submits a form data and is triggered when we click on a particular button. In tests, we have two choices. First is to execute the function directly and the second one, which is preferable, is to simulate a click event on that button. This can be done easily using triggerEventHandler from DebugElement. It has two arguments: the name of the event and event properties.

triggering events in angular unit testing

If the event is required, it should be created using the new keyword and then send as a parameter instead of null.

How To “Mock” Data Using Fake Dependencies

In most  cases we want to test particular code in isolation. But because components communicate with a lot of different services and each service has its own dependencies, it becomes complex (and the code becomes unnecessarily long) to add all dependencies just to test one functionality.

Instead, using out comprehensive Ignite UI toolkit for Angular, we can create fake dependencies that simulate the behavior of the real ones. This method is called mocking.

Using Jasmine spies

Jasmine provides us great functionality to create fake dependencies called spies. Let's give an example:. 

using jasmine spies in angular unit testing

Let's have one simple component with a method that is calling fetchData from DataService, which is making a request to an API to get some data and after that if there is a response we save this data into the component.  In this case, we don't want to test what is happening in the fetchData function. What we care about is the response. So here we can fake the response using spyOn method and then check if this method was triggered.

screenshot of how to fetch data in angular unit testing

How To Test Asynchronous Code and Angular Observables

Testing asynchronous code is similar with small differences.

testing asynchronous code in unit testing in angular screenshot code

If we want to spyOn a method which is asynchronous, we use .resolveTo() instead of .returnValues(). After that, if we are testing asynchronous method, we do two more things. First, we wrap the test in fakeAsync and then we use tick() which simulates the asynchronous passage of time.

The same applies if we are testing data from Angular Observable and BehaviorSubject which we want to display into the template. We need to populate the subject with .next and then use tick() to wait some time before processing to the next line.

testing asynchronous method in unit testing in angular screenshot code

Measuring Code Coverage

Code coverage is a metric which tells us which parts of the code are tested with unit tests. It discovers parts of the application that are not tested yet. While writing code, we must ensure that the overall coverage score is not reduced, but increased. It is accepted that 80% code coverage is a code goal to aim for. But try to cover as much code as possible. The more, the better. There is a built-in command that gives us a coverage report. All we must do is add the --code-coverage flag to our test command.

ng test --code-coverage

meausring code coverage in angular unit testing screenshot code

If we don't want to use the built-in code coverage generator from ng template, there are thousands of other npm packages you can choose from. Also if you are using Azure DevOps for development, they have also built-in functionality which we can use.

Finally, What Are Angular Unit Testing Best Practices

To wrap up, I would like to share a couple of best practices which you can adopt when carrying out Angular unit testing.

  • Make sure you have set up your Testing Module properly by running ng test from the command-line to begin compiling and running Angular Unit tests.
  • Name your Unit test in Angular properly – describing the method, the scenario under which the unit is being tested.
  • Build your functions as small as possible so the unit test can run fast and smoothly.
  • Always run unit tests in an isolated environment, eliminating any external dependencies.
  • Use spies from the Jasmine framework for the dependencies when testing services.
  • It is better to access the DOM with debugElement (providing an abstraction for the primary runtime environment) instead of calling nativeElement when testing components.
  • In case you run your app in the server, use By.css instead of queryselector since the latter only works in the browser.
  • Make sure you have at least 80% code coverage.

Ignite UI for Angular

Follow us on Medium and stay up-to-date with the latest Angular-related projects that we are working on. Give us a star on GitHub and help us to continue to improve our product by addressing any concerns, questions or feature requests in the issues section. We will continue to do our best to constantly improve our product experience to meet all your needs and build apps with ease.