02/06/2021

A guide for easy unit testing

 

To make it simpler for developers to overcome this challenge, our colleague Marko created the most effortless tutorial for testing each unit separately. To demonstrate to you the way Marko does this, we present the tutorial in its entirety:

You will need the following tech stack:

 

Jest – JavaScript testing framework and runner
React Testing Library – testing library built on top of DOM Testing Library by adding APIs for working with React components.
Test Renderer – provides a React renderer that can be used to render React components to pure JavaScript objects, without depending on the DOM or a native mobile environment

 

Unit Tests:

Simply put Unit test should do what it says it does: test just one piece of a Unit. Since this definition is a bit doubtful and doesn’t provide too much context, let’s further define what is considered under the term “unit test” and what action the unit test should perform.

 

Concepts and conventions

The unit test should respect the following concepts:

 

Test just one piece of code

Do not test multiple pieces of code within one unit test. One unit test should do just that: test one unit of code. A unit of code could be a piece of code that solves a specific problem domain written in the form of a: class, service, component, hook, util, or similar. For example, if your component is making interaction with 3 different classes and 2 different services, then these classes and services should be mocked.

By the term mock we mean that these 3 classes and 2 services should be replaced by some alternative code. Why? Because, otherwise the test would be considered an integration test, or to put it simply: now you are testing the integration of your code with 3 classes and 2 services.

 

Do not make any external interaction

A tested code should not interact with anything externally (avoid reading from disk, making HTTP calls, or similar). Why? Because it would simply slow down the running of the unit tests, or would require some extra setup before the tests are run.

 

Do not perform library functionality checkup

A tested code should not perform a checkup if some library has done something right or not. For example: if you are using a library like lodash there is no need to check if lodash performed something good or not, you should assume that it DOES perform as expected. And why this? Because you are not the maintainer of lodash, the lodash should do what it claims it does.

 

Test only code branching

Try not to “over-test”. Testing things like CSS classes, attributes, position, HTML structure or similar may be useful to keep track of, but this kind of test gets messy pretty fast and hard to maintain, which is why it is important to mainly focus on testing business logic. For testing HTML structure there is already a solution provided by Jest and that is snapshot testing. And for visual testing, there is Chromatic for performing visual testing.

 

Example:

Let’s simplify it: take a look at the code that covers all concepts mentioned above. We’ll peek into a simple component that displays a list of top GitHub repos:

 

unit_testing_tutorial_code 1

image 1: unit_testing_tutorial

 

Testing the component should follow this pattern:

 

Here is an example of such an approach:

 

unit_testing_tutorial_code 2

image 2: unit_testing_tutorial

Common pitfalls and edge cases

 

Partial mocking

Sometimes you’d like to mock something but just part of it and not the entire module. Luckily there is a way to do that in Jest. For example, the @apollo/client already provides a provider named MockedProvider so you could easily mock out GraphQL response, but sometimes you’d like to test out if the hook is called with the right parameters because any change in the code may result in different rendering, so we want to make sure that the exact request is being made each time. To do this you’d have to write something like this:

 

unit_testing_tutorial_code 3

image 3: unit_testing_tutorial

 

How to run tests?

 

To run the tests you’d simply have to run the following command: yarn test

 

Sometimes you may want to run just a single test file, and to do this in modern IDEs like WebStorm is just a matter of click-through UI. To do this in the console you’d need to run the following command: yarn test — -t ‘<name-of-the-test>’. So, if your test starts with describe(‘my-test’), then you should run the following command: yarn test — -t ‘my-test’

 

This is also another reason why is it useful to use describe() inside unit tests, because otherwise, you’d have to specify the full path to the test file, for example: yarn test src/TopGitHubRepos.test.tsx