Profits of unit testing
When I started with programming I did not care about automated tests. I always did some small app that was easy to test manually and if there was some bug nobody really cared. With this mindset I started my first job and I found similarly thinking people around me in the team including people from customer. We had some manual testers that checked every ticket and that was all testing we really did.
You can imagine there was quite a few bugs reported from clients that were found on production and there were few releases when we needed to rollback because application did not start at all or it was just some lumping cripple that was falling all the time. This one feature of Node.js applications. There can be some unhandled null pointer accessed somewhere in the app but the app itself will start and just wait until someone accesses null pointer so it can crash. With test setup we had, during test deployment testers checked only functionality that was changed in the tickets done in current sprint but could not test whole applications. There simply was not enough time. This led to one big issue during development process — we were afraid to create common packages, use them or change them because with that some other part of app would not be tested and could crash.
You can imagine how was the state of the codebase… A lot of copied code in a lot of places. Almost no util classes. And if there were some but you needed to change it a bit you created copy of it. With one word, it was a mess.
Of course there were some actions that we took to prevent these issues. We created longer window for test deployment, testers did try to retest whole applications etc. But with some data processing applications there might be edge cases you won’t trigger in manual tests.
During development phase it was not possible to do testing. Client did not want to spend money on this kind of nonsense. Thankfully when we somehow created stable apps and switched to maintenance phase the work we had reduced and because client wanted to keep the stable team in place he agreed that it is time to start doing at least unit tests.
So we created tickets and started with testing. You can imagine it was quite a pain in the ass. We set priorities and started testing most crucial parts of the code. We learned the hard way that testing code few months after implementation and sometimes code that you did not write yourself is much more time consuming than creating tests as you code. Sure it takes longer to do implementation when you need to add some tests. It can be twice the time. You also need to fix tests every time you do some extension or change to the code. And that is why clients do not like them and coders don’t give a shit about them as well. But writing tests to unknown code is much more difficult. First you need to read the code and understand what it does. You cannot write tests otherwise. And you can imagine how hard can some spaghetti that someone wrote in haste to fix some strange bugs be to understand.
Other headache was that none of us were really experienced in testing. So we needed to learn first and many times on our mistakes. I can say first tests were not good. We wanted to test big parts of code in one test, we did not test all edge cases or we did not add all asserts that would really test the functionality. But as we progressed we got better and in the end we got pretty solid test suite that covered all the most important parts of the code.
So as you can see we decided to write tests the hard way. But when we started writing tests we started to see the added value. We found many bugs in application which we thought was bugless and in perfect state. It was also easier to implement new things because before with no tests and documentation it was hard to reuse anything. With tests we got also good functional documentation of the code. And last but not least we got at least some stability in our applications. We did not need to fear that we will break half of the app anymore.
Because of these pros we started new projects always with unit tests. What can I say there as big benefit, our architecture and code quality improved significantly. We learned from test implementation that if you write some class without thinking about tests then testing is pain and in the end it is much more messy code. I have to note here that when implementing tests in old application we could not touch implementation. So creating test cases for some packages was veeeery hard. But when all functionality needs to be tested before ticket is approved the code will look much better and easier to understand.
Our productivity improved as well because we could work on applications that were dependent on other services that did not exist yet. It was enough to know what the interface will be. Then we just mocked these services and wrote application so it passed tests with this mocked interface. When the dependent services were ready we just connected our app did some end to end tests and were ready to go.
One thing to note here is that unit tests are not the solution for everything. It does not test communication between modules because all other modules should be mocked and if the interface of the module changes and it is not changed also in mocks the tests will pass even if the application will crash because of that. So we still needed manual retest during test deployments. But as the first sentinel unit tests are great and will add confidence to developers that they will not unleash demons when they push their changes.
So what did we learned about unit tests? Unit tests are great:
- to improve code quality and architecture
- to find hidden bugs especially in edge cases
- to save time for manual testers
- to save overall time of development
- to make developers more confident about their implementation
What do you think? Do you use unit tests in your projects as well? Or do you belong to that group of developers who think they write perfect code and do not need any tests? Let me know in the comments :)
Thanks for reading.
Cheers :)