Written by Vikash Tank, Blockchain Developer at Verv
We should all use automated tests in our projects. It can be seen as a useless process that does not make a difference if the code works, but I am here to convince you why it is a good idea and what benefits it can bring.
This article will walk you through what automated testing is, why you would do it, the benefits and drawbacks, and what to do after you’ve written your tests. We will also go through the positives of test driven development (TDD) and how this can further improve your working processes.
What is automated testing?
It is the process of writing code that tests each part of your system to ensure they are all running as expected. Automated testing can be split into two main types; unit testing is testing each individual piece of functionality, while integration tests test many parts of your system all linked together. It is good to know the distinction between both, but this article will focus on the benefits of automated testing as a whole.
Why write tests? 4 considerations
Some things you might need to consider when deciding whether or not to write tests are:
- Do you often write a piece of code that does NOT work first time?
- Do you take longer than 5 minutes to test that piece of code manually?
- Do you often find yourself developing the code further after its initial creation?
- Do other people work on this code?
If the answer is yes to any one of the above questions, you should probably think about writing tests. The creation of tests forces you to think about what the inputs and outputs of the code need to be. With this in place, you can quickly make changes to the code and know that once the tests pass, it does exactly what you need. Tests usually run much quicker than manually testing the code, especially if you have to manually test every single time you add or change something. The initial time spent setting up the tests is eventually outweighed by the time saved by not manually testing.
That said, writing tests of your code can be time consuming initially, especially if you know you can write the code quickly and manage to do it first time correctly. Learning the libraries that allow you to unit test and the tricks behind it mean that it may be very slow at first, but provide a lot of benefits later. It might seem better to not waste your time learning this skill, but you are likely to make the time back afterwards when your system grows and it becomes harder to fix bugs without introducing others.
An argument against tests is what happens if my tests are wrong? If I can have bugs in my code, why can’t I have them in my tests? Tests should ideally be clean pieces of code that do not have very complex logic, meaning you are less likely to introduce bugs. Given this and the fact you have to write BOTH the test and the code wrong to create a bug, your code is less likely to have problems. Although writing tests is some protection against bugs, if your tests and code are wrong in the EXACT same way, your bugs will go unnoticed. And that’s where QA can help.
If you work in an agile team and it gets hit by the plague (which recently happened here at Verv!), you could be the sole survivor picking off tasks that you may not have the expertise in. Imagine there are no automated tests put in place and the code base is reasonably large. You work your way through the code and add the functionality you need (as well as tests for new parts!). Since you are not an expert on the code and there is no way that within the time you have you are going to learn how the whole system works, how do you know what manual tests are required for the old parts of the system? There could be a huge document outlining each manual test in detail… but wouldn’t it have been faster to run automated tests? In seconds you know that you may have broken functionality that was already there.
In this case you do not have to spend a lot of time learning about the whole system, especially when there is nobody around to help, and you can carry on adding more valuable functionality to your projects. Tests usually provide a clearer and more logical description of functionality than a document. When adding new functionality you can see exactly which tests fail and gain a better understanding of how the part you have written affects the overall code. The existence of the tests allows you to trial and error new bits of code, as long as the tests pass and you are confident you have covered the code well. In this case you can work quickly and run the tests frequently for every change until you have iteratively reached a point where all tests are successful.
What happens if you go back to a piece of code after a few weeks and realise it is definitely not as well architected as it should be? You will probably have to refactor your code, one of life’s greatest joys! But this is less painful when you have automated tests already implemented. Since you will only be refactoring the code, and not changing the functionality of it, the tests can remain untouched. You probably do not want to change existing function names as these are likely to be in use by users/developers, so your tests can just be run unchanged after re-architecting. And if they pass you know for sure you did not ruin the lives of your team mates (assuming you covered all the functionality of your code in tests!).
I would encourage writing tests for all projects you work on. It is not rare that a simple bit of code that was only supposed to be used once, then has to be integrated or developed into a larger project. But ultimately this is up to your judgement.
Why it’s important to write the tests first
Writing the tests first (aka TDD) has more benefits than retrospectively writing the tests. Writing the tests first resists the temptation of adding tests that fit the code you have written, rather than code that fits your tests, meaning you are much less likely to overlook incorrect responses.
Writing tests in retrospect can also be a tough job, especially if you have not looked at the code for a long time. Knowing the specs that were decided at the time of writing the code and remembering how the code works so that you cover all the cases that may throw up errors is unlikely.
What happens after you have tests?
Write more tests! Once you’ve written a set of tests and your code is complete, it is useful to check your tests when you add more functionality or let your colleagues review them in your pull requests. Coverage tools can check that you have covered all of your system’s code with tests, but they won’t cover every possible issue. Weird ‘Boundary Cases’ where your code runs on the edge of what it is capable of, but should still work, can easily slip through the cracks.
Debugging can be a huge task and sometimes it’s hard to maintain a memory of which part of code protects against each bug. After writing your initial tests and finding a bug, it’s helpful to add a test that replicates the problem. This test is not a temporary piece of code, but something that will remain in your tests file forever making sure that bug, once fixed, never shows up again. The only way that bug will return is if you break your test, ignore it and release. The only thing more annoying than a bug is to find the same bug show up again a few weeks later, after the supposed fix. This can be pretty harmful for users who will really hate finding the bug multiple times. Anybody working on the code could accidentally revert a subtle change, which seems unimportant, and bring the bug back. So it’s always best to write a test for any bugs.
In the end, writing tests can be a huge help. Practising the skill and pushing past the initial time it takes to learn can provide all the benefits I have discussed. It might not always be straightforward, it may seem complicated or be a process that slows you down at first but eventually you will be more experienced, and like learning any other skill, become much faster.