Unit testing — Best practices testing Angular Applications

Today i want to share with you a very important topic that any programmer must know.

There are other articles or videos that talk about this, here is one i highly recommend to go through:

Link

I base my article in that video. The video is an speech in an important angular conference.

So, Why do we write test?

This is an important question that you must ask yourself. In my opinion the best answer is to don’t spend all the week debugging an app because of a bug. If we have good describes in our tests, we can detect any bug just with the titles lines. So that will really helps you in your work. And you could spend more time learning about the problem than debugging.

These are also the guarantee of your software quality, and if you go deep into this topic you will see that this will change your mind while you are programming, you will start thinking in tests and it will helps you to program with the best practices.

Well a little introduction about testing in Angular:

Unit test

  • Testing isolated small pieces of code
  • In general Most of our test should be unit test because it run faster and help us to detect bugs.

End to End test

  • Testing the whole workflow
  • We shouldn’t have lots of e2e tests but each of them should be a good representation of the real user scenario

Angular CLI gives us support to test Angular Applications

Testing using Angular CLI

Unit test

  • When we create a component, it automatically generate a template of a unit testing file
  • it help us to collect unit tests, run karma and display testing results on page

End-to-End tests

  • it can generate Protractor config
  • Can also collect e2e tests and run the tests

Let’s start with some common problems that we have to test in our applications.


UNIT TESTS

Asynchronous Test

It’s a common difficulty we face today, and angular has lots of async tasks, so we will mainly focus on that.

Angular by nature has lots of asynchronous tasks:

  • Promise (Microtask)
  • Timer
  • XHR (HttpClient)

Promise

  • The most common async task
  • Some other async tasks (time/XHR) might also be promise based

Here we have a demo delayed echo Server.

it’s an input where we can write, and we simulate server delayed.

How can we test it?

First approach:

it’s wrong because if we execute an async task (Promise) in a test, and we don’t tell the test to wait the answer, the test will finish before expect been executed.

2nd approach: Use done

Done is a callback function that tells test when it really finish, the problem is if something in the test throw an exception, because done will never happen so the test will fail because of timeout. This isn’t the error message we wanted.

We can use done.fail to handle this

This work but is a lot of code, so..

BEST PRACTICE

ASYNC/AWAIT

This is the clearest way. We run async task like sync tasks.


Timer

Here we have a demo using debounceTime, we usually use it to have a better performance in our UI, so i think we need to know which are the best practices to test it.

If we use async/await approach, we have to wait the time of the timer, so it will be slower, we need something faster.

How to test that?

  • Not echo : < debounce time
  • echo: >= debounce time

We need precise time control

BEST PRACTICE

fakeAsync Approach:

Everything is synchronous in fakeAsync zone.

it’s mainly used for testing timers, it’s faster and more precise time control.

  1. We need wrap our test in fakeAsync
  2. We can use tick(), to advance the watcher clock

XHR(HttpClient)

Options:

  • Jasmine spyOn
  • HttpTestingController

BEST PRACTICE

HttpTestingController

If we want to test the actual http request, and the httpclient call instead of a replacement response, we can’t use Jasmine spyOn, so the best practice will be use HttpTestingController.

HttpTestingController, intercept the httpclient request with a mock response.

Let’s see an example:

Here we are using httpclient to read a response from a json file.

Let’s test it!

  • Import HttpClientTestingModule
  • Fill httpMock with the injector.
  • intercept the request with expectOne
  • Use flush, that resolve the request by returning a body plus additional HTTP information (such as response headers) if provided.
  • Use httpMock.verify to verify if we have intercepted all the request called by httpclient in our test domain.

Summary

We have to use:

  • Promise — Async/await
  • Timer — fakeAsync
  • XHR(HttpClient) — HttpTestingController

I hope that these best practices helps you in your implementation and makes you a better professional!

You can ask any question you have, thanks a lot for reading.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade