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 1 - Don't worry about starting small

The first thing I want to cover in my "learning TDD" track is to not worry about writing seemingly meaningless or uninteresting code. First of all you never know what shape code will take in the future – the simplest of tests might help prevent a subtle bug. Secondly, it won't be long before you start to write more interesting code, so hang tight!

That said, for the first couple minutes I didn't even know HOW to start. I knew that I wanted to start with a core class in my domain (an Indicator). Indicators do all sorts of interesting stuff, but since I'm writing tests first, I don't even have an Indicator class!  To solve that little problem, I wrote the only test that made sense:

[TestFixture]
public class IndicatorTest
{
 [Test]
 public void CanCreateIndicatorInstance()
 {
  Indicator indicator = new Indicator();
  Assert.IsNotNull(indicator);
 }
}


Of course the code won't build. So I create a new class "Indicator" and make sure the default constructor is there. I know that in theory you're supposed to make the test fail - but making my constructor throw a fake exception for the same of making it fail doesn't seem worthwhile. It's entirely possible that I'll opt to go with only factories for my Indicator class, but for now, this is the quickest way to get started.

Next, I know that every Indicator will have an Name, so I write my next test:

[Test]
public void CanSetIndicatorName()
{
 Indicator indicator = new Indicator();
 Assert.IsNull(indicator.Name);
 indicator.Name = "Test Indicator";
 Assert.AreEqual("Test Indicator", indicator.Name);
}


So I go into my Indicator class and create a straightforward private _name field with a public Name property. Two points here. I could have easily made the test fail, but figured the broken build was good enough. Also, I agree that a public field would be the simplest solution here, but that violates our coding standards.

The Indicator class has a number of similar properties, so I write similar tests for all the ones I know about. Admittedly it isn't particularly fun and it doesn't feel too productive, but it's only a couple minutes of my time. There's an urge inside of me pushing me to take a bigger leap, but I keep it in check.

That's it :) I know it isn't much, but I had such a hard time accepting this way of starting, I figured others might also. I promise things will quickly get more interesting (though I think next post I might take a little break and go over nANT and CruiseControl.NET).

On a side note, as much as people talk about the importance of unit tests when it comes to refactoring, I honestly see them as even more useful when working in a team. The CanSetIndicatorName test tells the other developers on the project that someone expects the Name property to be null and NOT string.Empty when a new instance is created. If anyone changes my field declaration to _name = string.Empty, the test will fail and hopefully they'll think twice about their change, else risk breaking code somewhere they weren't away of.

Technorati Tags: , ,



Published Jun 23 2006, 09:49 AM by karl
Filed under:

Comments

Haacked said:

The first test isn't completely useless as it does test that the constructor doesn't throw an exception. If it did, the test would fail.  And yes, the second test would also fail if the constructor threw an exception, but the *granularity* of that test is less than the first test.

However, I do tend to agree that writing a test before you have a class to test might be a bit overkill.  I usually at least create the class and a stub method or property that throws a NotImplementedException().

You can see my approach in this post (the topic is on something else, but I happen to demonstrate my TDD approach as a side effect).
http://haacked.com/archive/2006/06/23/UsingRhinoMocksToUnitTestEventsOnInterfaces.aspx
# June 23, 2006 1:16 PM

karl said:

Nat & Haacked:
Thanks for the input, as this is a learning experience, I appreciate it!

I agree that it's a little silly, but not completely useless. You'll always have some unit tests that are going to be more complex than others and as such they'll implictly test other functionality. Should the simpler unit tests be elimited because the code is covered elsewhere?

The first test also tests that the Indicator class has a public default constructor. That very well my be a required behaviour. Again, other tests are bound to cover that functionality, but I must say I enjoy having a test devoted to it. It sends a pretty clear message about the need to have it.

Nat, you are right though, I could (and maybe should?) remove the Assert. If the code (a) compiles and (b) doesn't throw an exception I know I'm ok.
# June 23, 2006 2:06 PM

Haacked said:

I agree. You want to keep your fine-grained tests because when a more complicated test blows up, if the fine grained test still passes, you can exclude that from the cause. But if it fails, then it is the likely culprit.

Removing the assert is probably wise as it just takes up space.

However, if your test is to make sure that your class has a default public constructor, I would probably name the test accordingly or put a comment there.

[Test]
public void CanInvokeIndicatorDefaultConstructor()
{
 new Indicator();
}

or something like that.
# June 23, 2006 5:26 PM

Jeffrey Palermo said:

I know there is a lot of dogmatism around TDD for some folks.  The key to remember is that automated tests as a whole are assets that can be used continually to verifiy code.  Unit tests help to localize a failure.  The more I do TDD, the more pragmatic I become about it.  I tend to fudge the lines a bit and don't keep religiously to Kent Beck's guidelines.  If a test creates a safety net under a bit of code, then I consider it beneficial.  I'm using common sense as my guide more and more.
# June 23, 2006 6:23 PM

Dave Donaldson's Blog said:

# June 23, 2006 10:49 PM

Dave Donaldson's Blog said:

# June 23, 2006 10:49 PM

dotnetkicks.com said:

Trackback from dotnetkicks.com
# June 24, 2006 6:20 AM

Tim Dallmann said:

When you say: "I could have easily made the test fail, but figured the broken build was good enough.", I think you're missing the point.  The initial failure verifies that when your test actually fails, your test harness will report that failure.  The broken build failure doesn't catch this.  Without using the "Red" step of "Red-Green-Refactor", you risk having tests that appear to run successfully, even when they have actually failed.  It may seem silly and trivial, but it's useful nonetheless, especially as your tests get more complicated.
# June 26, 2006 11:00 AM

karl said:

Tim:
I certainly agree with you for complicated tests, but isn't it just overkill for these simple examples? Isn't Jeffrey's "common sense" approach better here (I'm asking sincerely).
# June 26, 2006 12:01 PM

raffourtit said:

About the first test.
When doing new development it might be a bit overdone. But I've just started adding unit tests to existing code, in that case creating the first test can already be quite tricky. And especially when starting with TDD I can see the point of making it (just to get the feeling of having somewhere to start). Working with a testing framework is something else then reading the tutorials.
# June 27, 2006 4:40 PM

Sam Gentile said:

I had yesterday's N&N cut short with a trip to the Jersey Shore. After a fine cookout day yesterday,...
# July 6, 2006 12:10 AM

Leave a Comment

(required)  
(optional)
(required)  

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

Our Sponsors

Free Tech Publications