Tests are important.
Writing clean code is the best thing you can do as a programmer.
But clean code without tests isn’t complete.
It’s like riding a bike very carefully, but in almost complete darkness.
It doesn’t matter how careful you are, you will hit something at one point.
Of course, writing tests doesn’t excuse not writing clean code.
If I had to choose between clean code and tests in a project, I would choose clean code, but it’s not an easy decision.
If a developer wrote bad code, but he also created decent tests, half of his programming sins are forgiven.
There is a concept called tests pyramid.
It states that in your project, unit tests should be predominant.
Unit tests are tests done at the method level.
You test your method, in isolation, for all the use cases it might encounter.
Ideally with Parameterized Tests.
I like Parameterized Tests because they encourage you to test a lot more cases than you would normally do.
According to the test pyramid, besides a lot of unit tests, that are the base of the pyramid, your project should also have some integration tests, that are the middle of the pyramid.
In integration tests, parts of your application are actually running, or even your entire application.
You want to test how different parts interact with one another.
Real databases might be used.
These tests take longer to write and execute and require more effort than unit tests.
On the plus side, they cover more of the system’s final behavior.
At the top of the pyramid, sit a few end to end tests.
End to end tests are done on a complete running system.
These tests are very expensive in terms of creating, maintaining and running.
For a long time I didn’t agree with this tests pyramid.
I thought it should be reversed, with end to end tests at the base.
What is the point of having a lot of passing unit tests, if your system is crashing.
I thought only end to end tests can guarantee a running system, so they should be focused on.
But I was wrong.
It’s true that end to end tests are the best guarantee your system runs as expected.
But they are so hard to maintain and run.
It takes a huge effort from the team to keep a lot of them up and running.
Eventually the team just gives up or becomes incredibly slow and frustrated.
Remember the viscosity symptom of bad code.
It’s the one where it’s very slow to do anything because of the environment your code lives in.
Unit tests on the other hand are incredibly fast.
They run in a few seconds.
As opposed to end to end tests that run for minutes or even hours or days in big projects.
It still beats days, weeks or months of manual testing.
But we are no longer living in the past to discuss that.
Unit tests are also a lot easier to maintain for these reasons:
They are easier to create, debug, and run.
If a unit tests fails, you go directly at method level and debug.
If an end to end test fails, you might not even be able to tell what module caused the problem.
Unit tests also don’t fail from random, inexistent problems.
I faced this a lot with end to end tests.
You can also run unit tests in an instant when working on a fix, you don’t have to wait minutes.
I also recommend test driven development.
In TDD you first write the test, but just enough to have it fail.
After that you go to your class and write a small piece of code, just enough to have your tests pass.
You repeat until the user story is finished.
It’s not easy, because you will be slower on the short term.
It takes a lot of discipline.
I will confess I am still struggling with maintaining such a level of discipline.
But on the mid and long term it’s the best way to write code and saves you from a lot of headaches.
This article is part of the “Test Pyramid and Test Driven Development” episode from the Clean Code course.
You can watch the Clean Code courses here:
– Watch Clean code with Java examples course on Udemy
– Watch Clean code with PHP examples course on Udemy
– Watch this Clean code with Java examples – Basics for free here AND get 2 FREE months of skillshare.com Premium