
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:
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.
- We need wrap our test in fakeAsync
- 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.