DEV Community

Marcin Wosinek for How to dev

Posted on • Originally published at how-to.dev

What’s the point of unit tests?

As a junior programmer, you might be confused by unit tests. To make things worse, tests used as examples often make their purpose more unclear. When you see stuff like
test example: expect(2+2).toBe(4); expect(dog.back()).toEqual('woof')
you are right to doubt whether there is a solid reason to spend any time writing them. Below, I show my reasons for writing unit tests.

What are unit tests

Unit tests are simple scripts that check whether a given unit—class, function, module, etc.—is working as expected. They are meant to be rather simple, to cover the happy path of the code plus a few edge cases. They contribute to the long-term success of a project because of the reasons I discuss below.

Speed up development testing

When you start building applications, the most natural thing is to test the code with the user interface. You can make this process way faster and more reliable by writing a script that will check the code for you. With tests in place, rerunning all of them takes no mental energy from you; you can do it as often as you feel like. This leads to a shorter feedback loop too, which will help you stay focused and productive.

Discover edge cases

Writing unit tests makes me think about edge cases—all the situations that are rare, unexpected, or wrong. When you write the logic, it’s normal to focus on the happy path, or what’s normal and expected to happen. When you write tests, you can set up checks for the edge cases and define what should happen in each of them. This makes your code more resilient in cases of unexpected inputs.

Ensure that your code is composed of units

When you add unit tests to your code, you see what is easy to test and what is not. As your code grows in size and complexity, tests will force you to break it into manageable pieces. This is great because it will help you take the quality of your code to the next level. Every segment that received excessive responsibilities will require exponentially more complicated unit tests. In those cases, it’s a good idea to stop and rethink how you organize your logic.

Interactive documentation

Your tests will become an additional resource for the next person working the code to figure out what it’s doing and how it’s supposed to work. It’s a kind of extra documentation, with bonuses:

  1. it’s often more precise than written descriptions in the actual documentation.
  2. tests can be run against the current code to make sure all statements are still valid; you don’t depend on a human to read, understand, and double-check the code.

Safety net for future changes

Unit tests execute so quickly that it’s a no-brainer to run them on any update, no matter how small the changes seem. You can set up your repository to run continuous integration (CI) and accept only changes that pass all the tests. In this way, you can ensure smooth change integration no matter the update:

  • minor update that “shouldn’t break anything.”
  • third-party library update
  • quick and dirty attempt at some fix

Unit tests protect the codebase against all minor regressions that they are covering.

Summary

Unit tests are an essential part of maintaining high-quality code. You can see it as one of the legs of a table:
table with 'code quality' written on it, supported by legs with: 'code', 'documentation', 'manual testing' & 'unit tests'
Sure, you can remove it, but it will make keeping a balance more complicated. Write them, and they will help you achieve good code quality and make your application safer.

Top comments (2)

Collapse
 
lexlohr profile image
Alex Lohr • Edited

Unit tests can be wrong on a few levels:

  • testing the test/mocks rather than the unit
  • testing the obvious
  • testing too much at once

Imagine you have a react component. You mock three event props and call them from the vDOM representation. Congratulations, you tested that your mocks work, appear in the obvious places, and not one of them is failing. You also managed to make all three aforementioned mistakes at once.

First, calling the mocks will merely test that they work, but they are neither part of your component nor of your actual application, so you just wasted time. You also tested the position of props in the vDOM representation, which should be a) obvious and b) could even be subject to change in which case your tests show a false positive. Lastly, you tested all events at once so if the test would fail, it'll be more difficult to know which event triggered the failure.

Try to make the most out of the least amount of tests. You want to test uncertainties. Also, your table is missing integration and e2e tests.

Collapse
 
marcinwosinek profile image
Marcin Wosinek

Thanks for your comment! This is a good topic for an article - how to write unit tests, and how to get the most value our of them.