As a newly arrived mobile developer at BAM, I encountered many issues with testing using Jest. To improve on this specific subject, I decided to tackle it directly and make it the number 1 focus on my mobile app project, mainly coded in React Native. I am using react-native-testing-library as my testing tool.
While I was becoming more confortable with unit and integration testing, I realized that I was always repeating the same steps, duplicating a lot of code and my test suites were becoming unreadable... it was time for some refactoring.
As I was starting this refactoring process for my tests in my mobile app project, I was looking into several articles treating this subject and realized several things :
? The articles I found were very technical and difficult to understand.
???? Refactoring tests seems like a long process. I need a way to do it faster.
??? They are very few coded examples, increasing the difficulty and the abstraction. I speak only code !
I started refactoring a test suite and decided to write this article with the learning I took from it. Here is what I learned :
Writing unit tests is an iterative process that encourages repetition and code duplication. This causes several phenomena:
A tool is available for all developers who want to make their tests readable, reusable, and easily maintainable: refactoring.
This article aims to give examples of possible refactoring, at several levels of progress and difficulty.
? Refactoring tests can be a long and tedious process, especially when you already have a significant amount of tests, so you might as well apply those principles right from the beginning.
Refactoring a test must not alter the understanding of the test itself. It is recommended to refactor only :
It is preferable to NOT refactor :
? When to start refactoring? If you find yourself :
...it's refactoring time !
Ok, enough rambling, let's get into the code. Based on a concrete example of a unit test on a form component, we will see 4 levels of refactoring, each of them enhancing readability and improving your development experience.
I wrote this example with React Native and React Native Testing Library. You may be more confortable with React or even another programming language, but don't worry, the steps of refactoring tests are the same.
Start by renaming your tests in a clear and uniform way, put hard values (string, number) in constants.
Our action event (changeText and press) are already clearer than before.
Refactor the most repeated action in your test, and put it in a function. This action should be used at least 3 times in your test suite.
At some point, you'll want to refactor several actions. Declare those in a render function specific to the test suite, making the implementation of the functions easier.
The refactored functions are now attributes of the tested component, and can be used in all your new tests.
? The presence of this render function allows to identify the test suites that have already been refactored, and the suites that still need some work.
Once you have strong refactoring foundations, you can tackle other repeated actions and develop your specific render function: the level of abstraction is up to you!
Here, I refactor the submit button as well as the action of filling all the fields and sending the form.
Here is the result after refactoring the test :
?? You might notice that the final example test is much longer and more complex than the original one. However, on a project, few suites contain one or two tests. You can feel the impact of refactoring when you increase the number of tests you write. If you don't feel the need to improve readability and reduce code duplication, it may be a symptom that there are not enough tests.
AHA Testing by Kent C. Dodds, to better understand abstraction in testing: https://kentcdodds.com/blog/aha-testing