The Problem: Resource Limits
So you just bought your shiny new piece of the hottest tech – maybe a new phone or a cool new smart watch – and you are itching to unlock all of the new bells and whistles. You power it up, man a few seconds feels like years waiting on this black screen. Wait, it’s been a few minutes now… 10 minutes… 15… will it ever turn on? Should it be doing this out of the box? Did I really pay all of this money for something that doesn’t work?! Didn’t anyone test this thing?!?!
Sure, someone, somewhere tested it. Well, they powered up in the emulator on their test environment – isn’t that good enough? “I didn’t have time to make sure it worked on the device, but it worked in my environment so it should work in real life, right?” Man, I’m never giving that company my money again; they obviously don’t care about quality control at all!
Sadly, I think most of us have had a similar issue sometime in our lives – and we love to blame the whole company, or even the IT guy we spent hours complaining to until he finally told us to send it in so they can have a look, for a problem that stems from nothing more than a limit on resources. This limit can be shown by the Fast-Good-Cheap triangle for project planning.
Pick two goals, and the third suffers.
You can have a good, well-tested product by your deadline, but it will cost you. Don’t want to pay? Well, you can have it by your deadline, but it won’t be thoroughly tested. Want it cheaper but well tested? Um, yeah, that’s going to take another couple of months.
The Solution: Unit Testing
So that’s it then. That’s the end-all be-all of software design, isn’t it? I sure hope not. I’d like to think that there’s a way to twist this triangle a little. Sure, we’ll always be bound by it, but can’t we have software that’s mostly
tested, that we’re pretty sure will work (and it will be maintainable for many years, you spent your hard earned cash on this thing!), but it won’t cost you your life’s savings to get it by a reasonable deadline?
There is a way to curb the “good” side of the triangle at least a little, and that is with Unit Testing
. If I could make the last two words light up in rainbows I would; unit testing has become quite the buzzword over the past several years. Still, developers know they should
be writing unit tests, but they don’t have the time
for it. And as long as I test it, that’s good enough right?
Yes – and… no. To explore this question we should first define what a unit test is.
What is a Unit Test?
A unit test is exactly what it sounds like. It takes a system’s smallest indivisible parts (units) and tests them individually, guaranteeing each piece of software works alone and by itself. Each unit test itself should be completely independent of the other pieces of software it is not testing, and should be scheduled to run on a timely basis to notify when new code does not work.
If you haven’t yet, read Justin Kaffenberger’s description on “One-Size-fits-all” supply chain software
because dependency injection, which he mentions, goes hand in hand with unit testing – we’ll get to that later – and we can steal his ExactaCar example because it works here, too.
[caption id="attachment_12967" align="alignright" width="300"]
"Each “part” was made and tested separately from the whole. When the basic ExactaCar was created, it was made with “standard” two doors, automatic transmission, basic tires, a basic engine, etc. While this standard car could work for most people, inevitably someone will come along who wants specific parts. This is where Dependency Injection and Unit Testing comes in handy – instead of creating and testing an entire new car, we can just take the basic car and replace the parts they don’t want with these new customized parts."[/caption]
To summarize Justin’s article, the ExactaCar is a car made with dependency injection - each “part” was made and tested separately from the whole. When the basic ExactaCar was created, it was made with “standard” two doors, automatic transmission, basic tires, a basic engine, etc. While this standard car could work for most people, inevitably someone will come along who wants specific parts. This is where dependency injection and unit testing comes in handy – instead of creating and testing an entire new car, we can just take the basic car and replace the parts they don’t want with these new customized parts.
Say you bought an ExactaCar with the standard manual transmission and two doors, but needed a more powerful motor and fat racing tires to meet the speedy needs of your customer. When we made this new motor and the new tires, we went ahead and made a testing facility (unit test) in our warehouse (codebase) for these new pieces. We verified each worked on their own before installing on the car, running some integration tests, and sending it out to you. Everything was perfect!
But now, your customer’s demands have changed. That old motor was fast in its day, but your competitor was able to get their car to have better fuel efficiency and faster speeds by adding a turbo. Luckily for you, we can add a turbo to the ExactaCar. It was even unit tested and integration tested with the basic motor, so we can just pop it on and you are good to go. Even better, during unit testing with this turbo, we found an unforeseen issue with adding a turbo to the custom motor, which if it hadn’t been caught would have caused an embarrassing motor failure after running exactly 179 laps on the IMS. Thanks to unit tests, you saved time and money and are now secure in your knowledge that your ExactaCar was fully tested.
Back to the Solution
So, back to the question: As long as the code is tested in some way that’s good enough, right?
Again, yes and no. It’s unrealistic to expect 100% coverage with unit tests, and by definition a unit test doesn’t cover I/O (like accessing a file directory or database). There is also no logical reason to try to set up unit tests on legacy code (older code from previous versions) since in all likelihood it wasn’t written in a way that allows for unit testing in the first place. So how can unit testing be worth your time?
You probably paid good money for your software, and not only you expect it to work “out of the box”, but you also probably expect new features down the road, and even changes to existing features. Luckily, when the developers wrote this new piece of software for you, they wrote unit tests as well. All of your old features’ unit tests are ran every night to guarantee new features don’t break existing features. Any new code written will also have unit tests, so this will continue into the future.
Several skeptics to unit testing and Test Driven Development (TDD) claim that unit tests are a waste of time. While I disagree with most of their points, unit testing does require some overhead. Instead of just coding and testing along the way, developers must have an intimate understanding of the feature they are trying to write. The better the understanding, the better the unit test. This means that a lot more discussion and planning goes into the project creating and any CNAs. It also means that at first, the biggest part of the triangle will be “good”, meaning that for unit tests to be possible, “fast” or “cheap” will have to be eliminated.
This will be worth it in the long run though, as the “good” section will get smaller once the unit tests are initially created. Keeping up-to-date unit tests for a codebase will catch most bugs before they become a problem, and will guarantee that new changes will not break existing code. In the long run, unit tests will be worth your time or money.
No comments have been posted to this Blog Post
Leave a Reply
Your email address will not be published.
Thank you for your comment.