There is no sense doing something we don’t have a reason or motivation to. This is why most of the people aren’t doing unit tests and they are right if they don’t understand why they should.
I wanted to make sure that the people know what is unit testing and why they should adopt the practice, so, I decided to do something about it.
In real life, as software developers, we have a simple task: to develop a solution that solves the user’s problem. Most of the times the users interact with our solution via a Graphic User Interface.
We do whatever it takes to get the GUI working so that we can deliver the solution to the users in time and on budget.
Before we deliver the solution, we run some functional tests. The purpose of our tests is to guarantee that the solution we will be delivering behaves as expected (It does react correctly to the user inputs). This tests are done on top of the GUI we built. We test the final product. We impersonate the user and we see if the GUI is reacting as expected.
This is the life of most of the people that don’t do unit testing. They aren’t wrong. It’s fundamental to see how the system reacts to the user inputs, to see if it behaves as expected. These Kind of tests is designated functional tests and if you are doing them, please don’t stop, just please hear me out!
Let’s consider the solution we just delivered to the users is a simple calculator that performs basic Math operations (sum, subtraction, division and multiplication).
From now on, we will be exploring different situations regarding our calculator solution and we will be trying to understand how can unit tests help us on each of the situations.
Situation A: There is a bug and code needs to be changed – the bug chain
If there is a bug, we open the source code project, spot the code responsible for the bug and change it right? But I want you to imagine that the coder that must fix the bug is not the same who wrote it initially. Finding the bug is not so trivial, it even gets worst when you didn’t write the code, so, you end up running the code in debug mode in order to spot the bug and then you keep debugging to test your code changes. After several debug executions you finally fixed the bug, but, there’s still a question at stake:
How can you be sure that your code changes did not affect the pre-existent code?
You can’t be sure unless you debug the code or run the manual functional tests, testing feature by feature. Our current example is a calculator, but, imagine if you were dealing with a really big application, would you feel comfortable doing that? Testing the entire application just to see if you code changes did not break the normal behavior of it? How much time will you spend on it? Most of the people don’t even do it. They end up sending the code changes to production without doing it, simply based on their faith and fundament less confidence.
They cross they fingers and then they pray for it to not crash in production and most of times another bug pops up and a bug chain is created. I have seen this happening. I have even done it and I know the pain of promoting changes without confidence.
How could unit tests improve the experience?
If you are going to fix a bug in code that has unit tests, you can easily know if your code changes are compromising the output expected from the other code units. You just have to run tests. No debugging, just run the tests and see if all of them have passed, if so, then, you code changes did not break anything. It gives you a little more confidence and saves you time. Unit tests take time to be written, but it’s obviously a trade off, you will make code changes and deploy with confidence faster. When you find a bug in production, a situation that the applications code hadn’t predicted and handled, you write a new test case to assert that the code is now handling the situation correctly. Tests cases are written by humans and they require the comprehension of what the code is supposed to do in order to find a way to assert if the code is doing the expected. Unit testing is not a Mayonnaise (add and enjoy). Its more like cooking a new food. If you want to be able to do unit testing, you have to code having that in mind. Unit testing is not an independent process. Some codes are harder to test than others and some are even impossible to test. Separation of concerns and abstraction can help in producing testable code. Lets not go deep into “How to make unit tests” and focus on “Why”.
Situation B: What does this code do? Should I change it?
I have found myself multiple times in situations where I was looking at code that couldn’t make any sense and I was like “Can I just remove it?”. I was messing with someone else’s code and I couldn’t be sure it was a good idea to remove the code but I was sure about one thing: “it was senseless”. A very hard exercise has to be done in order to make a decision. These are the steps i followed most of the times:
- Create a break point on the suspect code line
- Run the application in debug mode
- Interact with the application until the break point is activated
- Keep interacting with the application to understand the normal behavior
- Stop the program execution
- Comment the suspect code line
- Re-run the application in debug mode
- Interact with the application to see if it still behaves as previously
- Make a decision
It’s a long trip right? Imagine if you are debugging a JAVA EE applications that runs on an Application that takes at least 5 minutes to deploy because of the tens of applications it hosts. Imagine if you have to start apache server while you have skype running and both trying to use the same TCP port. There many things that can slow you down and make you waste almost half an hour just to remove a useless code fragment.
How could unit tests improve the experience?
Unit tests wont fix the apache vs Skype ports conflict, they wont even boost up your Java EE Application server startup. They will let you decide earlier by telling you if some code unit is misbehaving because of your code change. It is as simple as that. You don’t have to run functional tests to see if the user is being affected by your code change because you are changing code that might require some hard exercise to trigger from the GUI. What if the user experience is not being affected by your code change? You will deduct that the code is really doing nothing, taking the decision of removing it blindly. There is code that do not affect the user directly. For example: we want to broadcast a notification via a message queue every time the user sums 10 with 100 using our calculator application. This code does not affect the user that will be interacting with our calculator. We can even remove it, the user wont notice and wont miss it because he doesn’t even know its there. Testing code reactions based in functional tests can sometimes be deceiving. Code reactions are supposed to be tested in unit tests.
A few weeks after you remove the code that you were 100% sure wasn’t doing anything useful your boss tells you to put it back after telling you the losses the company has to deal with because of your excellent idea of refactoring the code. That’s the moment when you will wish to have written unit tests from the beginning.
What else?
We have explored two situations and we have seen how could unit tests improve the development process on each of them but it’s time to gather all the pros of unit testing in a single place:
- Increased coder confidence
- An expressive documentation of what the code does
- Improved code quantity – making code testable challenges the coder to abstract and separate concerns
- Cost effective – writing testable code and writing test cases both take additional time but they boost up the maintenance and reduce risks.
- Debugging new code is as simple as writing a new test.
- Everybody wins – the user gets a more reliable solution. The developer reduces the chances of spending the next weeks fixing production incidents caused by distraction. The company allocates the coder to do something else. The coder assigned to maintain the solutions has less headaches and the world gets better.
Are unit tests all you need to go bullet proof?
The answer is no. Unit tests can help you enhance your software process but don’t expect it to be as easy as getting the Mayonnaise on your food. It’s more like putting an elephant into your freezer, no matter how big your freezer is. It requires preparation and some engineering. Of course I’m talking about unit testing in cases of huge applications (forget the calculator thing).
Before you engage in the unit tester approach you need to remember why we test things:
“We test things because we don’t want them do embarrass us”.
If you can understand this, then you can understand the different test levels. Each of the test levels focuses on a different kind of embarrassment. Let me bring the remaining test levels:
A. Integration tests – the goal of this kind of tests is to assert that code units behave correctly when working together. They test the integration between different units. The same units that where isolated and tested individually in unit testing.
B. System tests – this kind of tests assert that the candidate item addresses the system requirements. This kind of tests focuses on software aspects. Scalability, performance, security and the list goes on.
C. Functional tests – they assert that the candidate component or solution works properly. There is no requirement judgment here. This level of tests simple focuses on the stability of functionalities the system delivers without questioning if the user needs them or not.
D. Acceptance tests – did we build the right thing to the user? This is the question answered by this kind of tests. They assert that the candidate item addressed the stablished user requirements.
The list you just read is not a hierarchy and I’m leaving the hierarchy job for you. Find out which goes after which one. I will give you a research tip: “V-model testing levels”.
Programmers are born as Cowboys but they must comprehend that software development is engineering and every engineering process is based on principles. Every engineering principle is based on research. Why not take advantage from the researches the others have done and have voluntarily exposed to us? We can do better software, and testing is a pretty good start for that.
You know its always a pleasure right? Then have a nice day 🙂






Comentários Recentes