Unit Testing Has Changed How I Write Software

posted on 08/18/09 at 01:11:26 am by Joel Ross

A few months back, I remember having a conversation with someone about my views on test driven development and unit testing in general. I told him that, while I understood the benefits, I hadn't been able to see any of them. As a result, I didn't do a lot with unit tests, unless it was an obvious case that didn't have a major impact on the rest of the code base.

Of course, the reality is the other way around. I never saw the benefits of unit testing because I wasn't disciplined enough to write the tests, despite understanding the benefits.

Looking back, it was a poor decision on my part. Once I took the time (read: it's the way things are done at TrackAbout) to actually do it, suddenly those theoretical benefits became real. But more importantly, I saw what happens when you lack those benefits. Older parts of our system aren't completely under test, and frankly, changing those parts of the code is both dangerous and time consuming.

I didn't realize how much my development style had changed until I started a new project recently. In the past, my style was to develop vertical slices of the application, starting with a UI, and building down from there. Why? Because without a UI, I had no way to verify functionality. But this time, I started in the middle, with the main service of the application. Or, to be more to the point, I started with the tests for the main application service. When I ran into a need for something outside of the scope of what the service should do, I created an interface for it, mocked out the interface, and developed against that. Once done, I picked an interface I'd created and started working on that one. I worked my way through all of them, until I hit an edge, such as database access, web service calls, or third party components. By the time I was done, I had the core functionality of the system written and tested.

And I hadn't written a single line of UI code.

The UI was fairly simple, and was pretty quick to create. But the amazing part was that I only ran into a couple of bugs in getting the application up and running. And they weren't bugs in functionality - they were issues with how I wired my components together (using Ninject of course!). Once i got that functionality working, I was off and running.

It was a new feeling for me. I knew it would work because I had proof that it did work. And when I needed to change something, I had a designated place to start making those changes (it's test class), and could ensure that it didn't have far reaching effects on the rest of the system.

I still have a ways to go. I find myself just kind of flowing as I start to write code and suddenly realize I have a whole section that isn't tested, and I have to go back and write some tests to cover that. I still struggle with testing at the edge - where I'm finally to the point of writing the code that integrates with another component - be it a web service, an actual physical device or just a third party component. I find myself leaving that to test through in the application. I also haven't figured out the best way to test the UI or the Javascript I've been writing either. But, even then, it's easier to find the issues with them because I know the stuff under it is already tested and verified.

I know I'm late to the party on this, but I prefer to think of it as fashionably late.

Categories: ASP.NET

16 comments »


 

16 comments

Comment from: Tyler [Visitor] Email
Wow, I'm with you on that first paragraph. Your right, I need to just do it to get it. So here is wishing you a good journey, and my plans to catch up.
08/18/09 @ 07:30
Comment from: Joel Ross [Member] Email · http://www.rosscode.com
Tyler,

Thanks for the comment. I know how you feel. And honestly, it's tough to get started. I had a couple of very good people to work with to lean on when I had questions, and that helped a lot. I got to watch how they worked and I slowly started adapting my style to mimic their style.

If you have someone like that, I'd definitely recommend sitting with them to get a feel for it. It helped me immensely!
08/18/09 @ 13:09
Comment from: Matt Blodgett [Visitor] Email · http://www.mattblodgett.com
Nice post.
08/18/09 @ 14:07
Comment from: Ryan Farley [Visitor] Email · http://ryanfarley.com
This is a really inspiring post Joel. I'm in the same place you were. I know *why* I need to commit myself to unit testing, I just have so little experience with it that I find it hard to start.

I basically work by myself, so I don't have many people to ask for guidance (except for short 140 bursts from my tweeps). Did you come across a good book you'd recommend to .NET devs? Also, for someone starting out, do you think it would be easier to start with a new project, adding tests from the start? Or would it not be too difficult to start with an existing project?

Thanks again for the great post Joel.

-Ryan
08/18/09 @ 15:55
Comment from: Erik Lane [Visitor] Email · http://blog.eriklane.com
@Ryan - I'll add my 2 cents (and more than 140 characters). I don't work alone but I have never worked with a team or on a team that did TDD...so I kind of work by myself. The book I tweeted was the one book I read that made it click for me. I'm sure there are better ones but it was worked for me.

Personally, I would suggest starting with a new project. That's what I did and it helped. It is easier to write tests for new code vs. trying to figure out how to break code apart so you can implement your tests. It can be done and you will end up doing it but it is easier after your mind set has changed.
08/18/09 @ 17:06
Comment from: Graeme [Visitor] Email · http://twitter.com/GraemeF
I would thoroughly recommend the book at http://www.mockobjects.com - that did it for me!
08/19/09 @ 03:03
Comment from: Benjamin Winterberg [Visitor] Email · http://bwinterberg.blogspot.com/
Nice post.
08/19/09 @ 04:01
Comment from: Jason Sankey [Visitor] Email · http://zutubi.com
Nice post Joel. This is exactly the kind of promotion great practices like testing need - unpretentious stories about real benefits. Much better than the holier-than-thou approach a lot of proponents take.

Re: your issue of getting in the flow and needing to come back and add tests later: I'm not sure there's anything to worry about. I happily do this but just make sure I have the tests done before I submit anything. If this turns out to be the more efficient path sometimes then don't fight it. I guess you just need to keep testability in mind because otherwise sometimes you churn out a pile of stuff that is difficult to test.
08/19/09 @ 05:19
Comment from: bob [Visitor] Email
Why did you need TDD to tell you to stop developing from the UI down?

If you think unit tests, make code you dont understand "low risk" to change you are nuts.

You dont understand the code, if Im your manager, you dont touch the code.

If Im a dev lead/mgr no WAY am I gonna rely on a self-satisfying test suite to validate your code.

Sorry, its clear your a newb. And thats cool. Testing is cool. But honestly, you dont understand the system, I dont let you touch the code. Period.

Unlike the self referential test, I am not an idiot.







08/19/09 @ 06:15
Comment from: Vijay [Visitor] Email
Hi Ross,

How did you create the mock objects? Did you use mockobjects (as suggested by one poster here) or JUnit or something else. Even I want to start with the test driven approach but am not able to find good starting points.

Regards,
Vijay.
08/19/09 @ 06:17
Comment from: Joel Ross [Member] Email · http://www.rosscode.com
@Ryan,

I would agree with Erik that starting with new code is easier than existing code. When I'm writing tests, I find that my code is more modular, and results in smaller chunks of code.

With untested, existing code, I usually find that the classes are coupled pretty tightly. Before you can even really write any tests, you need to break that coupling. After that, you can start to add tests. I find the process of breaking those dependencies to be tough. It obviously can be done, but if you're just starting out with tests in general, it'd be easier to start with a modular design.

The book Erik mentioned was pretty good, but I would also recommend Working Effectively With Legacy Code by Micheal Feathers. It focuses on how to break dependencies in code and write tests for that code. It's a great read, and while not .NET specific, it gives some great advice.
08/19/09 @ 08:39
Comment from: Joel Ross [Member] Email · http://www.rosscode.com
@Vijay,

I used NUnit as my testing framework, and I've used Rhino Mocks and Moq as my mock object framework.

I think it might be a good idea to write another post describing the process I used. That could be useful to help people get started.
08/19/09 @ 08:46
Comment from: Joel Ross [Member] Email · http://www.rosscode.com
@bob,

I think you're misrepresenting what I said. Unit tests are no substitute for acceptance testing before a release, and I never stated otherwise.

It's a nice theory that no one who doesn't understand the code can modify it, but the reality is that in a large system that's been in production for years, even the author of the code is going to struggle to have a clear understanding of every part of the code base. Having those tests as both a safety net and an example of how the code is meant to be used is very helpful in modifying that code.
08/19/09 @ 09:01
Comment from: Jordan [Visitor] Email
I think bob is just trolling. He either works in the ideal workplace or gets paid a lot of money to produce very little code churn.

I'd wager that 90% of software development involves a lot of people touching the code who don't fully understand the system it is part of. Obviously it would be great if everyone had a perfect understanding of what they were working on before they wrote a line of code, but to paraphrase a common saying: "It's a lot easier to ask for forgiveness (for bugs) than it is to ask for permission (to extend the deadline so everyone can get a complete understanding of the system)"
08/19/09 @ 19:22
Comment from: Joel Ross [Member] Email · http://www.rosscode.com
@Jordan,

Yeah, I figured as much. I tried to pull out the points he made and respond to those and ignore the bait.

I definitely agree with your assessment that most changes are made without a full understanding of how the system works - or, to take it a step further, why a system works that way.

Thanks for the comment.
08/19/09 @ 23:35
Comment from: Luke [Visitor]
I would highly recommend Roy Osherove's book, "The Art of Unit Testing". The nice thing about Osherove's approach is that he doesn't say "it's TDD or nothing". Obviously he thinks TDD is a very good approach to use but he also makes it clear that there is a lot of value in doing unit testing without TDD. This seems like a more practical approach for me. I would like to get to the point where I'm really doing TDD but there are several reasons why it will likely be a gradual transition. Anyhow, it's a very good book. He gets the reader up to speed very quickly.
http://www.amazon.com/Art-Unit-Testing-Examples-NET/dp/1933988274
09/11/09 @ 14:09

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)