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:
React Testing Library – testing library built on top of DOM Testing Library by adding APIs for working with React components.
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.
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:
image 1: unit_testing_tutorial
Testing the component should follow this pattern:
- Mock every module that would make an external interaction (HTTP request, read from disk, etc)
- Mock (or even better: spy) every class, module, or hook that you need to test if it’s being called with the correct parameters
- Describe what is being tested
- Write test cases inside describe
- Do a cleanup if necessary
- Make sure you provide default behavior if you mocked out some module or function
Here is an example of such an approach:
image 2: unit_testing_tutorial
Common pitfalls and edge cases
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:
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