Many times, when I take a legacy code, I feel so glad to see that the code has a very high level of test-coverage, and it fails rarely. So at this point I feel like that I’m in a green field project and I strongly believe that I can maintain this code and add more features…
For my surprise, when I open the first test file… I feel desperate when I discover that I have been reading code for a long period of time, trying to understand complex structures and loosing my focus about the test approach or forgetting what feature I want to implement.
This situation might feel very similar for you. In fact, you don’t even need legacy code in order to live this experience; this could happen with your own code, so we will undertake a few tips where we can see how to improve our test readability and not lose focus.
In the first place, we will have a React Function Component that displays an specific message depending on a property value:
So when we take a look at this component we know that we will receive an
exercise param on props, but we didn’t know anything about the structure (this is good), only that it has two fields: one that is called
tags for being iterated, and a second one with is a
warning message that only should be displayed when it’s different from
undefined. Easy, right?
But when we enter to the test-file:
This works fine, it gives us a 100% coverage of all possible bifurcations of our component… but it’s really difficult to read (imagine that those 20 commented lines are really in the file). We would have a file that is 108 lines of code long for only testing 3 functionalities.
I personally understand the author of this code because your
exercise value changes in each test, and using a
let or override values for each one probably is not a good idea.
On the other hand, the tests names are
should display the warning and
should not display the warning but in a simple sight, I don’t know what is the condition for this to happen.
Finally, I think that when we said
should display a list of two elements it was near to be correct because not using a specification doesn’t define that the data is an array and doesn’t indicate that the displayed component is a
Chip either. Nevertheless we don’t want to know if it’s exactly two or more elements because it can make the developer believe that is a special condition of our domain.
Let’s start renaming the test to declare our intentions:
I based the test naming process on the
given-when-then cycle. In my opinion this is a better approach of test naming because we can specify whether displaying the warning message or not. In most cases there is no need to actually specify this structure but that’s the logic behind it.
Finally, I remove the specification of 2
tags because this probably could have been written for one of these two reasons:
- An old domain specification that is not present in the component anymore.
- A mistake of the developer trying to make the test more specific.
Now we will try to hide structures from our test body. Depending on the language we are using, we could use some different techniques. In most cases, a
function with dynamic params would be used, but
extending the real
class with a
Mock Class in order to set default values in the constructor — unless specified — is a valid solution as well. In other words, we need a dynamic builder.
As we can see in the code, we can generate an object with the default values, or only set the values that we need for our test. This is a good thing for me: if I need to add, remove or modify the
Exercise structure, I only have to pass those values to my builder, and my tests wouldn’t know about data structures.
Now, we only need to import this function an refactor out product definitions:
At this point, we are focused on the code of our tests and can detect other improvements that with 77 lines more we weren’t able to detect.
If we are familiar to use tests, the first thing that is in our mind is the idea of using
beforeAll statements to define our wrapper because this actions are executed each time. Keeping with that idea we would lead us to depend directly on the props that the component receive at the moment of its construction, and that’s not what we’re looking for.
However, this doesn’t stop us to, at least, create a little function helper for creating our wrapper and returning our common part of the
Last but not least, we have two remaining lines of code, but the body of our test is more simple and it represents exactly what we need to know about the test and the component functionality. Additionally, this makes it really easy for us to add new features.
I sincerely appreciate you spent your time reading my article, I’m glad to share this information with other people in order to improve the actual way of testing our applications.
I would be thankful if you could share this with other people to give other vision of how we can keep improving our work as developers every day.
You can find me on my social networks:
Adrián Ferrera (@AdrianFerrera91) | Twitter
The latest Tweets from Adrián Ferrera (@AdrianFerrera91). Full Stack Developer | TypeScript 💙 |…
Adrián Ferrera González - Full-stack Developer - Lean Mind | LinkedIn
Creando React Native Apps con... En esta ocasión vamos a esbozar como crear una app en React Native y como añadir…