Strategic testing overall and test driven development in particular scare developers in the beginning. At first, we don't see the full power of the process; there are a few common defensive objections we come up with to resist the new "awkward" technique.
I'm dedicating this chapter to addressing your potential concerns. ☺️
Let's play a virtual Q&A
Tests require more code to write, therefore will slow down the development process, right?
This is correct - if your project is tiny. If it takes a couple of hours to put together and never come back to it, sure, it's reasonable to spend an extra hour poking around and call it a day!
Unless it's a "tiny" program that's called by a big one, which in turn, is launching a spaceship... 😱
Jokes aside, the more code you write, the more automated tests will help you. Here's one of my favorite diagrams that illustrates the benefits of automation:
There's only so much of increasing manual work you can tolerate!
With manual testing, the test time will grow exponentially with the size of your main application as you'll need to not only test the new parts, but also re-test previously tested parts - even if you believed they shouldn't be affected!
Incorporating automated tests creates a situation for you similar to what the the diagram above illustrates - after making some effort it starts working for YOU and you can chill! Well, your graph won't be as horizontal, as you'll still need to write tests to cover new functionality; however, the rest will be taken care of!
In addition, you'll always be improving your code through refactoring.
Using tests - that can be done without risk. Refactored code will be easier to read! As you know now, a big portion of a developer's work is to read code. Comprehensive code also contributes to instating the speed of the development process.
So, in the long run, writing tests makes the development process faster - quite the opposite of our initial claim!
Refactoring means doing extra work instead of having the correct code the first time, right?
Good point! ☺️
This is indeed true! However, "getting it right" is surrounded by a number of variables, including both technical and business objectives. Refactoring presents an opportunity to challenge previous solutions and support the natural evolution of software products: expansion, improvement, or repurposing.
Everything has room for improvement!
Writing code is a creative process (despite the alternative common opinion!).
Yes, eventually it's black and white, it turns into zeros and ones, it either works or it doesn't. But there's a long, beautiful road of creativity that leads us to a destination! Painters paint in layers, composers juggle notes, novelists go through tons of paper in the search for perfection!
And in terms of software engineering, that is called refactoring!
Tests are written to test production code. Tests are also code themselves, so they would also need some tests, right?
Another good point! ☺️
The tests and the production code are tightly connected, so that the production code, in turn, tests the tests. 😲
It's like a house of cards: some lean to the right (production code) and others to the left (the tests). The two sides support each other!
Tests illustrate the presence of bugs when they are red. But an all-green test suite doesn't guarantee the absence of bugs, does it?
This is very much true. However, an all-green test suite does decrease the probability of bugs being present. It's neither possible nor reasonable to cover all the possibilities.
Let’s look at a parachute as an example: it works most of the time, but unfortunately, accidents happen. 😱 Still, knowing that wouldn't encourage you to jump out of a plane without a parachute, would it?! ✈️
Test Driven Development is about rules and not creative thinking, right?
Yes, there are rules to follow. And creative thinking is always encouraged - however, we must ensure our creativity serves our purpose. Structured tests allow us to keep this in check!
It may appear boring, but, hey, you gotta make sure you have clean dishes before you can cook a gourmet meal! 🍽
It would be challenging to work with a large project that hasn't incorporated tests, right?
This happens often. While more and more teams understand the importance of tests and incorporate them from the start, you are bound to encounter a legacy code from back in the day or a new project that gets off the ground promising the tests will be right around the corner but that never reaches that corner despite an ever-growing code base.
This is the reality and YOU have to be the change! 😎
Big projects are like icebergs - there's lots to discover beyond their tips! To be able to incorporate tests, the code must be well architected - testable. If that's not the case, it must be refactored. But without tests, it's dangerous to dive into refactoring as it's easy to break something. So, to test, you have to refactor and to refactor, you need tests - sounds like a catch 22. 😵
If possible, start with a part of the code that you can test without changing too much. Then, use the new tests as a safety net for further refactoring and extending the test coverage to the entire code base. Ideally, it's best to start testing when adding a new feature, which helps to ensure nothing around it is going to break. Then, proceed by doing the same to the further additions and alterations of the original code.
Introduce tests gradually. Start small, progress slowly, and, eventually, make a BIG difference!
Unit Tests do not allow testing UI, do they?
This is correct. It's not trivial to test the user interface. For example, it’s harder to programmatically identify what color a button is than to ensure the right color by testing the function that’s feeding it to the button against an expected value.
For this, it's necessary to separate the logic of the visual composition and the visualization itself. In our example, the logic that gives the value to the boolean should not take place in the same class that allocates the color to the button. In MVC, everything is done in the controller so it can be challenging.
We've chosen to be developers, not testers, right?
Oh, trust me, writing tests does not turn you into a tester! It makes you a professional developer! And it allows you to make some friends in the QA department and with Tech support groups because they won't have to deal with your broken code all the time. 😉
The truth is that many of your bugs may appear as the same old bug to testers, when, in fact, you might be planting an army of new ones while working with a piece of code.
Believe me, testers have enough on their plates! They are one step closer than you to sometimes frustrated users! 😳😡
So, do your best to protect them and they will protect you!
The bottom line
Software is an extremely sensitive system. At times, a seemingly minor adjustment can cause a crash of an application. We are surrounded by much less error-sensitive systems in our lives: if a nail is removed from a house, it won't collapse; if a cell in a human body dies, a person will stay alive!
On the other hand, we are all familiar with a system of accounting. An accounting error can destroy a business or put its leaders in jail. This "science" is much older than computer science and so it took its time to solve the problem of hyper-sensitivity.
700 years ago, double-entry accounting was invented. In double-entry accounting, everything is entered twice, on the asset side and the liability side. Assets and liabilities follow very different mathematical logics. But in the end, the two values of liabilities and assets must be equal. If they are not, there is an error. This system makes it possible to detect errors extremely quickly with great certainty.
In programming, it's the tests and the code that form a double-entry alternative. The two components make it possible to detect errors very quickly and to ensure the overall strength of the system.
No accountant goes without double entry. Should programmers be less professional than accountants? Do their mistakes have less impact on the business? I trust you get my point!
What's more, accountants update the data on the asset side and the liability side at the same time. That's exactly what we do in TDD.
So, all in all, "the more you sweat in training, the less you bleed in battle!" 🛡👩💻⚔️
Incorporate tests from the start.
When working with an existing code base without tests, refactor parts of the code to allow introducing tests.
Keep your books in check! 🤓