Purpose of the Article: To spread awareness of increasing code coverage adequately in React Native, for which limited resources/material is available on the public domain
Intended Audience: Mobile Developers using React Native Framework
Tools and Technology: VS Code, React Native, TypeScript, Jest
Keywords: Unit Testing, React Native, Testing Library, Jest, Mocking Libraries, Code Coverage
Unit testing is the process of testing tiny parts of code in isolation to ensure that they are accurate. However, the question that often looms in the mind of a developer is how much unit testing should be done, and the answer to this lies in the Code Coverage.
We will use the same repository which we used in Part 1 of the blog. Suppose you have not seen part 1 as of now. Please visit it first before going through this article.
Link of the repository used: https://github.com/kp47/UnitTesting.git
Link of the website for using free APIs: https://reqres.in/#support-heading
What is Code Coverage?
This is an essential measure for unit testing. It’s useful for determining the efficacy of unit tests. It’s a metric that shows what proportion of source code is executed during testing.
Let’s understand this with an example; let’s say we have a login page, and on submitting proper credentials, login will succeed.
The developer writes a test case for this scenario but is it enough?
The developer missed writing the test case where if one or more than one field is kept empty, then the UI should display an error message stating invalid input.
Hence, we can say that the developer did not cover all scenarios, and the coverage will not be 100%.
Key Aspects of Code Coverage
There are four sections of code coverage.
- Statement Coverage
- Branch Coverage
- Functions Coverage
- Lines Coverage
Let’s understand those one by one. To understand the sections, let’s take the following example.
- Statement Coverage
This method verifies whether all potentially executable statements in source code have been run at least once. It is a method for making sure that every line of source code is tested at least once.
This may appear to be a simple process, however, while assessing Statement Coverage, it is vital to approach with caution. The reason for this is that a condition in the source code may or may not be executed depending on the input data.
This would indicate that not all lines of code will be tested. As a result, several input value sets may be necessary for the source code to address all of these scenarios.
E.g., If the developer provides data in a way that only if the condition works then lines written in else condition would never get executed, which will decrease the statement coverage.
- Branch Coverage
The purpose of this coverage is to make sure that each conditional structure’s branch gets executed in the source code. For example, for 100 percent Branch Coverage, the test in the above code should cover all of the ‘If’ statements as well as any surrounding ‘Else’ lines.
Branch Coverage will be 100 percent if value sets (2, 3), (4, 2), and (1, 1) are used in the provided code. Because (y > x), the first ‘If’ branch is executed when data sets (2, 3) are used. When the data set (4, 2) is used, the condition (x > y) is true, and the second ‘If’ branch is executed. The ‘Else’ branch then evaluates to true, and the data set is executed (1, 1). As a consequence, 100% Branch Coverage is guaranteed.
- Function Coverage
As the name indicates, this method evaluates the amount to which the functions provided in the source code are covered during testing. All functions in the source code are tested throughout the test run. Again, we must test these functions for a variety of values to verify that they are thoroughly tested.
A source code file may include numerous functions, and a function may or may not be called based on the input values given. As a result, Function Coverage’s purpose is to ensure that we have all the needed functions.
For example, we will call this complete Function Coverage if our tests invoke the ‘TwoNumberAddition’ function even once in the source code above.
- Condition Coverage
Wherever there is a condition in the source code, the result is a true or false Boolean value. Condition coverage determines whether the tests cover both true and false values. The code’s Condition Coverage is regarded full when each occurring condition in the source code is checked for both true and false states.
Condition Coverage in the following code, for example, will be 100% if value sets (2, 3) and (4, 2) are used. (y > x) becomes true and (x > y) becomes false when data sets (2, 3) are used. Similarly, when data set (4, 2) is used then (y > x) evaluates to false and (x > y) evaluates to true.
Before starting to write test cases make a list of what not to consider in the coverage
When it comes to unit testing, business logic is considered the most valuable area of your code to test; hence, it is very important to understand what needs to be covered and what not. In React Native, you cannot cover everything. There must be some files that need to be excluded in the consideration of coverage.
You might have some strings file or constant file or, for that matter, a colors file to maintain the theme. Although you can increase the coverage for them, I suggest not to. Is it worth it? There is no logic written on these files. It i is best to ignore them from the coverage and indulge yourself in writing test cases for functionalities.
To remove them from coverage, use the jest configuration written in the package.json file or the separately written jest config file as follows:
Plugins We Use
Although we had tried a lot of libraries like “Detox,” “Enzyme,” etc., , we are using “react-native-testing-library” as a plugin for writing our test cases.
Come Fly with Me
If you’re a fan of GTA Vice City, then you would know what I am talking about… ‘Cheat Codes.’
Yes, even React Native has its cheat codes when it comes to coverage. There are a lot of tricks to increase some percentage of coverage just by following some simple tricks. I am going to show you two of them in this blog which I most widely use.
Rule 1: Don’t have export default in your styles. This is my stylesheet code.
If I export default my styles page and then check the coverage, the style page is 0% covered, as you can see in the below image.
This is annoying, but a minor tweak makes it cover 100% of the file. The trick is to have a stylesheet assigned to a constant and then export that constant like in the example below:
Now, if you check the coverage of the style file, it is 100% covered.
Rule 2: Re-render the screen before writing any test cases. This will increase your coverage to all the useEffects that you might have in your code.
Most of the time, you will see that none of your useEffects are getting covered. This can be easily covered by re-rendering the screen as follows:
Coverage report shows exact percentage coverage for each file. It also tells you which function, condition, or line is not getting executed. This is a helpful feature to have. Whenever we hit the following command,
yarn test –coverage
React Native by default creates a coverage folder in the root of the app. Inside the folder, there is another folder called Icov-report, and inside that folder, there is index.html. If you click on the index file, you can see the coverage report in the browser as well, and it is interactable, so you can click on any file name and check which section of code is not covered.
The code coverage looks as follows in the terminal.
I hope you got the idea of what code coverage is and how we can increase the coverage for our project. For any further questions or doubts, reach me on my personal email email@example.com.