With the above test, i flawed to write tests for individual functions for those classes. When the server boots up, it also runs a set of classes which rely on the same functionality to check if a device exists. A little, but really shortened schematic:
Add device: Web interface -> Device service -> Package Manager -> Device manager.
Device discovery at boot: USB monitor -> Peripheral service -> Driver service -> Device service -> Package Manager -> Device manager.
Two scenario’s depending on the same functionality. And both are responding in the same way, with an unsupported device. And as the project grows, you want to get things done as fast as possible, and thinking i will write the unit test later on. Well later on really did become, later on, i started to implement a package manager for the web interface, and got some odd results, i had to handle a null value instead of an exception saying that there is an unknown device. A little schematic: Web interface -> Package manager -> Device manager.
So starting to search for the reason, i could not directly identify where it came from because the package code was written a while ago and i first “connected” this code to the “Device Service”, and went on writing the code which are relying on this device service. (The reason for this is that we initially could begin testing devices attached to the systems). So, i started to create some tests to identify where the problem started. It took me about writing 9 tests to see where in the chain the problem raised.
Here comes my flaw. I began writing a unit test for the package device manager, ran it, and was expecting an exception, but instead i got a null value (the function i got it from is quite big and complex). Somewhere in the package device manager a “null” is returned when a device does not exist, where it should throw for example an “UnknownDevice” exception. Because it returns a null, a lot of extra code is executed with unneeded “if then else” evaluations. We are primarily developing for the raspberry pi, so we want to execute as less code as possible.
I had to rewrite some stuff, and clearing at least a 100 lines of extra code which i did not need anymore by throwing an exception instead. This was code i did not have to write if i spend some time to implement a test. Writing the test just cost me a minute, writing and removing these lines of code a lot more. So i immediately created a task in the task list of what we still have to do: “Update Unit tests“. This task is now picked up as a task which has to be picked up first, with the code changes it brings.
Because of not writing the unit tests at the moment a functionality is done, and delaying them. A lot of these design flaw like problems started to arise when i started to test. It also causes a big delay in implementing new functionalities. While the code does run correctly, The unit tests show that there are implementation flaws, and thank god no functionality problems (pfew!).
At this moment i’m rewriting the configuration system because the current implementation could be done a lot more intelligent. Because of this, new features relying on a configuration item, or items, can then be implemented a lot faster with lesser code. Unfortunately, at this moment, I have a lot to rethink of, i’m already seeing a lot of improvements, nicer structures, less quick hack code and even bugs are disappearing. So i’m sure it will come out for the better.
My personal conclusion
Yes, writing unit tests takes time away from development. But does it really? When you encounter a bug, and even do some extreme trace logging, it can be very time consuming to find the error. You have to spend time to search, discover and identify the reason of the bug. What you have to ask yourself is: “Does the bug hunting process cost less time then writing one or multiple unit tests?”. I think most of the time the answer will be no. Unit testing is not only for the programmer self, but also for a team, or a successor. How often do you work on a project without tests, can be quite a stress right? Not even to speak about on starting on a project from a fellow programmer who is not available anymore, and there is a newly discovered bug in a still unknown part of the application.
I’m not saying that unit testing is the utopia, tests can be implemented badly (I have seen a lot of tests depending on the outcome of a functionality, and not on the expected result), but it will bring it a lot closer.
Something i have to keep in mind myself.