What is Brahmāstra?
For the people unfamiliar with the term “Brahmāstra”, let me tell you that its the supreme weapon of all. Even powerful than Thor’s Mjölnir.
I have chosen this as the title of my topic not because we are talking about war today. But if you are a developer with several years of experience the very often than not you might have got the feeling that you are barehanded. A sense of fear runs down your spine. Some inner voice tells you that if you try to modify the code here, it might break something somewhere else which you don’t even know about.
In such a situation, many times, we often try to take a safer approach that might include writing sub-optimal code, code duplication, or any other type of compromise.
But do we really have a choice? How do we fight the army of unknown bugs when we are already barehanded? The answer is to deploy your most powerful weapon; Brahmāstra, your automated tests.
By automated tests, I mean all the unit tests, integration tests, UI tests, API tests. Tests are our best chance, tests are our best weapon.
Advantages of tests
A well-written test suite not only helps test your code but also the dependent code. The tests will give you the confidence that you need while developing a feature or fixing a bug.
Apart from helping in development, they also help you get familiar with the code quickly. Many people believe that the tests are more useful in understanding the code than the documentation. One simple reason is that tests provide a working example of how to use the code, what are the edge-conditions, and what kind of output can be expected given a specific input.
This also means that onboarding new developers consumes lesser time. Moreover, the new devs will also have the confidence to play around the code knowing that the tests got their back.
This will lead to lesser frustration, good team spirit, and lower attrition.
Principles of writing good tests
Tests can be of different types based on the code they test and the setup required for them. My main focus for this topic is the unit and integration tests. Because the UI tests can vary drastically depending on the type of the system, a topic for another day.
In general, my opinion is that the tests should follow these general principles.
Different source sets
The source sets for the unit tests and the integration tests must be different. Mainly because they are written in a different manner and they test different slices of the application.
Moreover, the integration tests use a different set of libraries/frameworks than the unit tests.
Another important criterion is that we should be able to run these tests anywhere the underlying platform (JRE/Node) is installed. No additional setup must be required externally.
Any setup required by the tests must be done by the tests themselves and cleaned up once completed. This means the tests must not have any side effects.
Test a single unit
A test must focus on a single unit of code and contains a single assertion. Does this mean that in languages like java we have only a single assert() statement in the test? Definitely No.
The focus here is one logical unit of test and one logical assertion. This means that if the user object has five different properties, and we assert all of them, this still means we are asserting a single logical entity, user.
Covering multiple units in a single test might lead to higher maintenance costs. One change in system might lead to cascading changes in several tests.
In my opinion, this could prove to be the single most important factor in our test suite. If the tests take too long to execute, the developers might not run them at all. Leaving the heavy lifting to the CI systems. This will lead to the late detection of failed use cases defeating the purpose of tests altogether.
Important as the business code
Don’t treat your tests as second-class citizens. Duplicating code in tests is not OK. Not following proper coding standards in tests is not OK. Creating unnecessary dependencies in tests is not OK.
Take care of your tests so they can take care of your code.
Have good coverage
What amounts for a good test coverage ratio can be agreed upon by the team, but generally, anything above 80-85% is considered as an acceptable limit.
But keep one thing in mind, never write tests to increase coverage. Instead, it should be the reverse. Higher coverage should be the by-product of well-written and well-thought test cases.
So these were my two cents on the importance of tests. Apart from the technological aspects, I tried to focus on the human aspect as well as explaining how they might affect our work and our psychology. Let me know your thoughts in the comments.