The Beginning of My Unit Test Adventure
My first job was working at a company that had a large group of software developers with a legacy codebase containing over 1,000,000 lines of (C and C++) code. While some groups developed new features, my group was primarily in what I call ‘firefighting mode’. A mode where tasks had to be completed yesterday, because they are urgent. There was no time to make things better… just fix the latest bug. There also were no automated tests. Not one unit test. No automated system tests.
By my good fortune (it would have been a coworker, but he happened to be on vacation at the time), I just so happened to go with part of our team to Arlington, Virginia for training on becoming a certified ScrumMaster. The group that came back became one of the first scrum teams in our company.
This scrum team was devoted to developing a specific new feature that one of our customers needed. As we started to develop that feature, we started separating what we called “the BIG” into smaller, stand-alone packages. Each package also had unit tests. But let’s first talk about what I mean by packages and the big.
Big Monolithic Executable vs. Small Packages
This code got compiled to go onto a module that fit into a larger system. Each module had the ability to have a debug header put on it. In order to compile the code, it took anywhere from 15 – 45 minutes or so for a clean build (and these were 8-core machines!) to 1.5 – 10 minutes for a build with objects already existing (the link step took forever). Once that build finished, it would take anywhere from 0.5-5 minutes to load the code on the module, then another 2-5 minutes for the module to boot up once the debug code was on it.
This… took… FOREVER! So even for testing simple debug code, the feedback loop was maybe 7-10 minutes best case before you could test the simplest of changes.
We started taking pieces of “the big” (anything that was part of that big monolithic piece of code) and separating dependencies so they could be compiled independently. Then we wrote a new main program that just ran Google Test unit tests. Our feedback loop went from 7-10 minutes down to about 10 seconds to compile AND TEST code.
Believe me… this is a HUGE, HUGE, HUGE game-changer!
Now, not only does the code compile extremely quickly, but my manual test can now be automated and run faster than I ever could have hoped for by typing commands into a command-line interface.
And Then There Were Unit Tests
I was one of the first people to start writing unit tests for this new package. It had several singletons in it, and there was an order dependency on which ones were instantiated before others. It probably took me a day or two just to write a unit test that instantiated all the singletons we needed to even start testing (use TDD to prevent this complexity from happening!). Getting that first unit test written was a beast. But after that… I had an automated test. Oh my gosh. Even if I am bad developer, I can still have the computer make me be good since I have to pass all these tests.
This process has revolutionized the entire way I view the development process. This is why I am so interested in software automation. I can setup some infrastructure, whether that be unit tests, continuous integration tools, continuous deployment processes, or other methods, that can make me much, much more efficient. Besides, I don’t really enjoy testing all that much anyway. It’s much more fun to develop code. Now I can test by developing more code, and I don’t have to test very much at the end since I have already tested it for the most part with unit tests I’ve written along the way.
Do yourself a favor, and whenever you write code (or better yet, before you write code using TDD), add unit tests to verify the functionality of the code. Your future self will thank you.