Introduction to Unit Testing

Gus
Frontend at Accenture
4 min readDec 7, 2022

Since I began my journey with JavaScript frameworks/libraries I always struggled with unit testing. How does it work? How to implement it? Is helping in my development process? Now that I understand it a little bit more, I’ll share some basic concepts.

Photo by Ferenc Almasi on Unsplash

What is Unit Testing?

It is a software development process in which every small part of your code (called units) is tested in an isolated environment to determine whether they work correctly or not.

This process is not liked by most of the developers because it takes time to understand and apply it correctly, but once you dominate it, it is a great tool.

Some of the benefits I have found by doing unit testing in my projects are:

  • Prevention from unwanted code changes

Let’s say that you have a component with certain logic already programmed, and someday the client asks to add new functionality and you start moving functions, variables and end up doing a little bit of refactor (it always happen). If you don’t have unit testing in place you won’t have a way to determine if the refactor you did impact the existing logic. On the other hand if you have unit tests for each different scenario you can run it and easily know if something is not working as expected.

  • Analyze the code behavior

Unit testing helps us to understand our code better, and to determine whether a scenario is expected or not.

  • Find issues in your code

Sometimes when you are writing the test cases you find different scenarios that you weren’t considering and that potentially will cause issues to the application in the future. If you do your unit tests correctly you should be able to cover every single scenario, expected and unexpected. This will increase your code coverage that plays an important role in your project, and we will talk about this in the next section.

Code Coverage

The code coverage helps us to answer two questions:

  • Are these enough tests?
  • Do I need to add more tests?

Why do we need to ask these questions? Well, first of all when we are writing tests, we need to understand if the tests are covering all the edge cases, if there is any branch missing, if all the statements are covered or if I’m missing a function.

The code coverage helps us to establish how much percentage we want to cover from our project, there are different types of code coverage. There is global coverage overall the project and there is component scope coverage, usually in the projects I had worked on, we use 70% or more for every coverage.

There are different types of coverage that check different aspects of a file.

  • Branch: Check branches in your code. Different paths that your code can take. If, else, do, while statements.
  • Function: Check if the function has been called or not.
  • Statement: Check if the statement was executed, i.e., Variable declarations.
  • Line: Check if the line was executed.

For each type you can determine a different percentage in your test configuration, and that would mean that you will need to reach that percentage on every type to have a successful test. If not, the tests will fail.

The anatomy of a test

Usually there are 3 steps in a test. First, you prepare your environment of the code you want to test, then you trigger some action to start the process you want to test (i.e, call a method) and finally you get your response and compare with your expected result.

In the next example I’m using Jest, the most popular JavaScript Testing Framework, maintained by Facebook.

test('should return the expected value', () => {
// arrange
jest.spyOn(service, 'internalFunction').mockReturnValueOnce('mockValue');

// act
const result = service.myFunction();

// assert
expect(result).toEqual('expectedValue');
});

Arrange — Mock all the information needed to run your test.

When you are testing some functionality in your application, you don’t care about the response of an HTTP request or if an external process needs to finish first to run your code, that’s why in this first step we mock all the environment around, this can be functions, variables, services, etc.

In the example above, imagine that “myFunction” calls “internalFunction” and then with that result do something and return something else. We are mocking the value from “internalFunction” because we don’t care about the logic inside this function since probably this will be tested in another isolated environment.

Act — Execute the code you want to test

Usually, we use a call to a method or do a user interaction to trigger something in our code. Here we can save the result in a variable to compare it with our expected result afterwards.

Assert — Handle the expectations

There are multiple ways to make an assertion, but most of the time we compare the result from the method or user interaction to an expected result. Since all the environment is under control, we know exactly what the expected result should be.

Conclusion

Unit test has pros and cons, but if I can agree on something is that ever since I started using it I do more organized and maintainable code, because when I’m coding I already start thinking on how I can test it.

I strongly recommend to start using it in your projects, at the beginning can be hard to adopt this new process, but at the end will pay off once you start to see the benefits.

Let me know what you think about unit testing, are you already applying it in your project?

--

--