CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Karl Seguin

.NET From Ottawa, Ontario - http://twitter.com/karlseguin/

TDD Lesson 5 - UI and Database Unit Testing

We unit test because we think we get more out of it than we put into it. The upfront cost in time, which is paid for in money by our employers and clients, is paid back by easier maintenance and more stable code. Sometimes the payback is great, sometimes it isn't and sometimes you'll have the necessary information beforehand to make that determination (and sometimes you won't).

When it comes to unit testing the UI, I'm of the opinion that the value just isn't there. Maybe the tools have gotten better since the last time I seriously looked at it - fair enough. I'm certainly not saying the UI shouldn't be tested, simply that unit tests might not be the most effective tool. That doesn't go for the entire UI though - a lot of components can be tested just as easily as anything in the business layer. I'm mostly talking about classes that site in your App_Code folder (assuming your using one) and help support the actual UI.

And this is where I ran into problems. I couldn't add a reference to my web project from my unit testing project - huphmmm. Maybe I was just doing something stupid, but knowing how the 2005 web project model works, I wasn't particularly surprised. The new project model is one of the main reasons I spend less time in the newsgroups - just too many questions/confusion about it (I'm sure it's died down, but when 2.0 came out, it was all we'd hear!). So I switched to the 2005 Web Application Project Model and solved my problem (after having to add a lot of protected declaration). So I'm now able to test my GetIndicatorIcon(Indicator indicator) function just like any other. (On the positive side, I think this motivates developers to move this code outside of their pages/user controls and intostraight up classes. Just because you're in the UI doesn't mean everything needs to be a codebehind).

On the flip side, I think there's tremendous value (at least in my case) in unit testing my data layer. I haven't started yet, but I pretty much plan to follow Roy Osherove's approach  (also available @ msdn). I plan on being able to install a fresh database from code (just ExecuteNonQuery all my create table/sproc/function and the necessary inserts). In the past, RedGate products have helped get this off the ground. Create it into a temp database from my TestSetupFixture, and drop it in my TestFixtureTearDown. If Roy's transaction approach doesn't work with a particular test, I can drop the existing database and start from scratch with ease. The approach might be less fun to manage for a large database, but I'm pretty sure it'll fly straight for me.

 Technorati Tags: , ,


Published Sep 11 2006, 08:52 PM by karl
Filed under:

Comments

Jeremy D. Miller said:

Karl,

The trick with unit testing the UI is to separate out as much of the behavior and screen workflow into code that isn't bound to the ASP.Net or WinForms runtime.  That's why the MVP/Humble Dialog Box patterns are getting so much attention right now.  It's not really unit testing by any definition, but Selenium or Watir are fairly approachable for automated web testing.

As far as the database testing, be mindful of the execution timing.  I would do the database object creation as part of the NAnt script before you run the unit tests, not in the unit tests themselves.  I've seen people drop and recreate a temp database in unit test harnesses.  It just leads to a slow build that decreases productivity.  

I like to do the database testing by just building a skeleton database on each developer workstation.  In the SetUp() or TestFixtureSetUp() we wipe out the tables that are being used in the tests and put in new data.  I'd actually recommend taking a look at FIT style testing for any kind of set logic.  It should result in more readable tests than you could achieve in xUnit tests.

You could also try using Guid keys or some sort of randomized data to avoid data collisions.

Regardless of how you do the database testing, you're going to want to separate the "slow" database tests from the "fast" in memory tests so you can run them separately.

Slow builds == bad

# September 12, 2006 2:02 PM

karl said:

As always, I'm grateful for the input Jeremy.

I was planning on marking my TestFixture as Explicit and running it as a separate build than the CI (i.e., a nightly build). That said, I'll look into what you suggest.

# September 13, 2006 12:10 PM

Jeremy D. Miller said:

If you're using CCNet, it's really easy to set up a staged or cascading build to run the slow stuff in a secondary build.  

# September 13, 2006 12:19 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

Our Sponsors

Free Tech Publications