I still remember the first time I had someone talk to me about automated unit testing for a project. The library mentioned was Kent Beck’s JUnit, but such tools have been around for a long time.
Like many of the cool toys, crutches, and methods we have today, the notion of automated unit testing as we know it in the Java world originated in the Smalltalk community. In fact, the first xUnit library was built for Smalltalk, and it too was written by Kent Beck.
Remember the first time you heard about automated unit testing? I bet you reacted much the same way I did.
Automated Unit Testing is a Waste of Time!
I Do Fine Without Automated Unit Testing
The year was 2004, and I was working for a stalwart member of “big corporate america.” I had been brought onto the team because I knew a thing or two about putting together a Java web application, and the team needed someone with that skill set.
My first major project went off without a hitch, and I was busily working on “the next, big thing” when I received a fly-by from a teammate asking if I could help with a consult on one of the team’s high-visibility applications.
“Sure! You bet!” I replied before going over for a demo and walk-through of the codebase.
The application was essential to day-to-day business operations, and I figured helping them out would be a nice feather in my hat. I was doing alright, but feathers are great to have, right?
Remember the campaign strategy for Desert Storm? Shock and awe! That’s exactly what I felt as I received my guided tour through the application and the nasty defect that caused that initial fly-by.
My shock grew by the moment. The application was essential to business operations, but what a beast it was.
There was no clear separation of the view from the server-side. The controllers had business logic in them. The business logic had view concerns in it. It was a marble cake of functional concerns!
Things had gotten so bad that the deployment team had removed the application team’s ability to deploy until fresh eyes came in and blessed new changes. Everyone hoped that, since I successfully built and deployed a Java web application, I could rescue this vital application.
We had to get the existing bug fixed both quickly and in a way that wouldn’t blow-up in our face again.
I had always leaned heavily on project structure and design, coupled with frequent execution of the system being built. It got me through college. Heck, it had done me just fine in my professional life up to that point.
What do you do when the thing you start with is a mess though?
Automated Unit Testing Sounds Cool, But It’s Too Expensive
Someone brought up the suggestion that we should write automated unit tests. Then, each time we changed something we could run them.
It sounded like an interesting idea, and the notion of writing code to test code appealed to the geek in me.
I sat down and put some brief thought to it. By my rough calculations, we would easily write more test code than deployable code. Maybe even double!
No, there’s no way we could ever get done in time if we wrote tests. We just needed to focus on structure and design and pull out every stop we could to grease the development process.
Automated Unit Testing Might Be Okay … For Some Stuff
There’s Nothing Like Having a Mentor
The year was now 2006. Time moved on, and so did I.
I continued to lean on structure and design, along with manual testing and visual inspection, to get projects done. I never did forget that mention of JUnit, but I never acted on it either.
I was still doing okay with my methods. Why rock the boat?
Then, one day, a teammate was helping my pod farm neighbor with JUnit and EasyMock. I was more than a little curious to see how a person that knew what they were doing actually did unit testing, and – let’s face it – I’m a bit of a busy body when it comes to people talking near me about code-related things.
Go ahead and laugh, but I wear that badge with pride!
I noticed how my teammate would run the test and it would either light up red (a failure) or green (a success).
That was kind of neat, but I still didn’t see how tripling my codebase (two-thirds of it being test code) could make me go faster. I couldn’t even envision getting done in the same time.
It just didn’t make sense, and I was about to dismiss it as yet another flashy thing that people like to latch onto to make themselves feel important.
My teammate then started showing my neighbor how dependencies could be removed and replaced with mocks. The mocks could be told exactly how to behave, and you could tell the mock what values to return when a given method was called. It even let you raise exceptions!
Now, I don’t care who you are – that’s just cool. And, as it turns out, it was the thing that made me write my first automated unit test ever!
Who Knew Testing Could Be Fun?
Remember how I said I liked to build an app little by little and then do manual testing and inspection? Remember how I said it worked for me?
Well, I did. … and it did.
I could finally see how these unit tests would do the same thing though, and they had the added benefit of being able to test each class without building, deploying, and executing the entire application!
Plus, it doesn’t take a genius to figure out that the computer can examine the outcome and judge its correctness much more quickly and reliably than a human can – especially if multiple fields are involved.
I started writing more and more tests. At first, I reserved the unit tests for complex things. However, I quickly saw the savings of not having to build, deploy, and execute the entire application.
My arrogance caught up to me one too many times for my preferences too. That, really, was the clincher for me. As I sat and considered why I would avoid writing tests for simple code, I had no good answer.
The code was simple. The test would be simple. … and then I would know that the code worked!
Writing code and knowing it functions the way you intend it to is an awesome, fun thing. Of course, errors can still happen as the result of bad requirements documentation or misunderstanding.
There also seem to be some QA people that believe firmly in requirements by defect. You know, they file a bug because they don’t like something and want it changed.
If you’ve never had that happen, you haven’t been developing very long!
Automated Unit Testing Required … Or Else!
Oh My God, Someone Gave Me a Team!
Fast forward again. The year is 2011, and I’ve been given my first team.
I’d had teams before, but in responsibility only. Say what you will, but it’s just not the same. There’s no feeling in the world like having someone trust you enough to lead a team.
It’s like when you get your driver’s license and go on that first solo drive!
I was working under contract at the time, and the contract stipulated that we should have at least 80 percent code coverage. We didn’t have to test the web controllers though. They were deemed too difficult to test.
Nobody puts much logic in web controllers though, right? That’s a perfectly reasonable out.
I wasn’t about to let the contract stop my team from testing the controllers though. By now, I knew the value in testing everything. I’d learned my lessons – the hard way – and I wanted to make sure my team learned too.
I only ever had one person challenge that, thankfully. I never have enjoyed the “managerial responsibilities” that come with leadership, but it’s a two-edged sword.
If you are the person steering, you have to steer – even when you don’t want to.
My solution? I threatened to get our boss involved. He worked hard to improve after that!
When is Ninety-Five Actually Seventeen?
Like I said, our contract gave us an out on the web controllers. My team was testing everything, but the tests we did on web controller changes were not seen in the reporting, and I wasn’t content with that.
So I did it! I added the web controllers to the coverage report. Surely there wouldn’t be much impact, and then I could actually monitor that tests really were having an impact.
My findings? I had three in rapid succession.
You see, when I ran the build, the reporting got sent to the entire team. It went to the contract team, and it went to the client part of the team too.
The client part of the team held their heads very high with a ninety-five percent coverage. Now, that’s how you test an application!
Woot! Woot! Woot! Woot!
The coverage report hit my inbox. I scanned it quickly, died a little inside, and then had to just laugh out loud.
The coverage had dropped to seventeen percent – a reduction of seventy-eight percent!
I received an immediate call. It was the lead developer on the client team, and let me tell you he was not happy!
Needless to say, I immediately took the web controllers back out of the coverage report and re-ran the build.
What were my learnings?
You Should Always Test Everything
The contract had given us an out, and people had used it! There was a lot of untested code. Much more than I ever expected.
It made sense though. I was having problems reconciling the high defect rate against the coverage percent. When I saw the real state of things? Well, that’s why I laughed out loud.
The Web Controllers Contained Business Logic! Gasp!
When people have a choice of two different places to put things, and one is faster and easier, a lot of people are going to go for the easy one.
These people don’t care about design or the welfare of the application, they just want the win. Unfortunately, it’s not really a win – it’s a net loss.
Some People Just Want to Look Good – Project Be Damned!
I will never understand the response I received when I included those web controllers in the coverage report. Any reasonable group would want to dig and learn how such a dramatic decrease would be possible – just by including the web controllers!
This group? They preferred to act like a herd of ostriches and stick their collective heads right into the sand.
Automated Unit Testing is a Gateway Drug to Test-Driven Development
Nowadays, we’re in 2016. Things have changed a lot for me as time has gone by, and mostly for the better.
The single biggest change? I’m now a TDD fan!
It sounds a little nutty to people who haven’t done a lot of automated unit testing, but there really is a lot of value in test-driven development. Yes, even more than writing unit tests after the fact.
Let’s look at some.
No More Tests That Don’t Fail!
I know you’ve done this! Admit it!
You write your code, and then you start writing your test. You go to mocking things, and you do it wrong. Your test passes.
This happens because you’re just throwing stuff into your test to get it done. The test is an afterthought, and this is the consequence.
If you always make sure your test can fail, you’re probably going to catch this. However, if you don’t, the consequences could be that you wind up in a long game of “Go Fish!”
When you write a little test (enough to fail), then write a little code (to make it pass), you’re in an entirely different mindset. You’re more focused on the test, and allowing the code to evolve as-needed.
No More Guessing When the Code is Done!
When you practice TDD, you know instantly when you are done or if something more is required.
It’s simple really: Have you represented the requirements in the test? Does it pass? If you can tick both of those boxes, you are done.
No More Code That Isn’t Tested!
This is my favorite one. I’d regularly hit ninety-five to ninety-eight percent coverage just making sure I had tests written for the code I wrote before I committed it. However, when you write your test code first, and only write code needed for your test to pass, you get perfect coverage!
As long as you don’t add any missing property accessors (hey, I have a get and no set!) you’ll keep your coverage perfect. After all, those missing methods can’t really be missing if they’re never used.
Wrapping it Up
No matter how you practice unit testing, you have likely noticed that when you break the code, the tests show you where. They bring light – very quickly – to exactly why what you did was bad, and help steer you back into working code.
It’s like having x-ray vision into code quality.
I hope you’ve gotten some good take-aways from this article, but I’d like to draw attention some specific ones that I hope you leave with:
- It’s difficult to turn a manual tester into an automated tester, because they feel they are delivering more value to you with their current actions than they could if they practiced automated testing.
- There’s nothing like having a mentor to help that manual tester become passionate about automated testing.
- The more you test, the better off your project and team will be.
If your developers are testing manually, and you don’t have someone on staff that is really good at unit testing, consider bringing in a hired gun to help out. Just make sure that whoever is teaching has a strong background and is a good teacher.
I’ll write more about testing and TDD. In fact, my current plan is to release a free tutorial that will take a person on a guided tour of how TDD can be applied to a typical Java web application.
Sound cool? Leave me a comment below!
I’ll also be covering things outside of software development that relate to my experience running successful Agile projects. If you have something specific you’d like to focus on, please let me know.