Frontend unit testing
Tags: javascript, angular, webdev, testing
Published: 2021-12-23 10:32:13


Javascript was invented a few decades ago. Initially was used for small in-browser interactions. Though in recent ten years javascript passed through huge evolution. It is mostly related to the invention of SPAs (single page applications) and NPM package manager. Which gave superpowers to the already known Javascript. With those transformations, the code base started to become larger and more complex. A larger code base is more vulnerable to errors. In this article, we will see how to make a codebase resistant to errors. At least to reduce part of them.

**What is Unit testing?**

We are not gonna go into details about what the Units are. Briefly saying, software engineering best practices suggest separating the code into small components or modules. Such separation will increase the maintainability and readability of code.

Going back to our topic. Unit tests are responsible for keeping our code correctly functioning when introducing new changes. They are small interactions with specific functions or components. As a result of these interactions, unit tests expect to receive specific responses from the component/function. At least the core functions of an application should be tested.

To simplify, let’s use a real-life example. You want to buy a box of six eggs. What should you check?

* Is it a box of eggs or something else

* Are there eggs at all

* Are there six eggs or less

* Is there a broken egg

* Are they the size you wanted



**What if I don’t write unit tests?**

Nothing happens. At least from first sight. But as the larger your codebase grows harder becomes to maintain it and debug. Sometimes you may introduce a bug and don’t mention it. Then after weeks of development, it pops up and crashes the application. You start panicking and debug every bit of your code. After hours or even days spent debugging you figure out the problem was in a small mistake.

What if somebody told you could’ve avoided this situation? Or at least reduce the number of them. One of the solutions is Unit tests.

Sometimes it may seem boring to write tests. You just want to be in the free flight with the code with creativity fireworks exploding every single minute of the work. Though I’d like to warn you (like your grandma) if start falling you didn’t take a parachute.

Yes, there are cases when you don’t need any tests. For example, you develop a prototype that never will go to production. Here is the goal not to develop a stable app, but a proof of concept.



**How do they work?**

In the modern javascript environment, there are a variety of libraries making testing comfortable for developers. Some of the most popular are [Jest](https://jestjs.io/), [Jasmine](https://jasmine.github.io/). They have built-in methods. The core are “expect” methods. Which take a method/component and check whether the output is the one we expect to receive.

Let’s take jasmine for example.
``` typescript
    describe("A suite is just a function", ()=> {
      **let **a;
    
      it("and so is a spec", ()=> {
        a **=** **true**;
    
        expect(a).toBe(**true**);
      });
    });
```


**When to write them?**

There are a variety of approaches to unit tests. Each developer has his own preferences related to testing. Also, each company has its guidelines and requirements for testing software.

TDD approach suggests writing tests beforehand and then implementing code. However, this approach fits systematic software development when almost everything is described already in the technical overview. In many cases, you choose solutions and write methods in the process. That means methods written before tests.

Even in that case I strongly suggest writing tests step by step. You’ve written a method, write unit tests. Otherwise, you end up with a long code with many methods or dependencies involved. And when you will start testing it can turn into a strong headache.



**Mocking data**

The goal of unit tests is to check specific units such as class, component, function. That means you need to ignore all non-relevant code. Yet many components have external dependencies on third-party libraries or other components. In this case, within the unit test we need to replace these dependencies with static code which will simulate responses and states.

Jasmine for instance has already built-in methods for mocking data. Such as **createSpyObj** or **spyOn**.



**Test coverage**

Each time you build tests ensure they are really testing what you need. There are many cases when test passes and it is green, but in the reality, it didn’t check anything or checked the wrong statement.

Another mistake could be not putting expectations to the test. But this case is easier to discover because testing frameworks such as Jasmine will write “**NO EXPECTATIONS…**” before each tets case lacking expectation. Even the test will pass, though you will see it’s useless.

Be careful with test coverage. You have to check whether all or most of the cases are covered by the test.



**To conclude**

The main goal of the unit tests is to provide stable work for development teams.

Let’s recap:

* Test **all** possible case **scenarios**

* Check the level of **code coverage**

* **Mock **any external classes/services

* Don’t test **third-party** libraries.

* **Write tests** as soon as you progress with the development. Don’t wait until the end

Sources:

* [Jest](https://jestjs.io/)

* [Jasmine](https://jasmine.github.io/)

* Cover gif. [“Completely obliterate the car”](https://imgur.com/gallery/tPPNeaJ).