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

Christopher Bennage

Our WPF book is now available!


Confidence in your code

First, I highly recommend Kent Beck's Test Driven Development: By Example.  It's an excellent book.

I mentioned Beck's book, because it is there that I gained an insight affecting the way I'm writing unit tests.  (So Christopher, you're saying that one of the seminal works on unit testing has affected the way you are writing tests?  Um, yes, I am saying that.)

Kent asks a question about when you should remove duplicate or overlapping tests.  His answer was that if it doesn't decrease your confidence in the code, then it's okay to delete it.  (I hope I'm getting that right, my copy is loaned out at the moment.)

My current project uses WCF to handle communication from the desktop client to the server.  We have a set of interfaces for our services shared in a common assembly.  When I create a new interface, I always forget to decorate it with the ServiceContract attribute, or I'll create a DTO and forget the DataContract/DataMember attributes, or (and here's the worst) I'll forget to add the PrincipalPermission attribute to the actual implementation of our services!

This has been bothering me for a month or two, and finally it dawned on me: why don't I write tests for all of this?  I'm not confident in the code, I'm fearful that I'm forgetting things; let's write tests and remove the doubt!

Here's what one of the tests looks like:

[TestFixture]
public class Service_interfaces
{
	private const string ASSEMBLY = "SomeAssembly";
	private const string SERVICE_NAMESPACE = "ServiceInterfaces";

	[Test]
	public void must_have_a_ServiceContract_attribute()
	{
		bool atLeastOne = false;

		foreach (Type type in Assembly.Load(ASSEMBLY).GetTypes())
		{
			if (type.Namespace.Contains(SERVICE_NAMESPACE))
			{
				atLeastOne = true;

				object[] attributes = type.GetCustomAttributes(typeof (ServiceContractAttribute), false);
				Assert.IsTrue(attributes.Length > 0,
							  string.Format("The {0} does is not decorated with the ServiceContractAttribute", type));
			}
		}

		Assert.IsTrue(atLeastOne,
					  string.Format("No service interfaces were found in {0} in the namepace {1}.",
									ASSEMBLY,
									SERVICE_NAMESPACE));
	}
}

So I am just the last on the bus?  What do you think?  Is there a better way to handle this? 



Comments

Keith Nicholas said:

I talked about this in

designingcode.blogspot.com/.../as-little-unit-testing-as-possible.html

I think there's a subtle difference between what your saying....

TDD is generally about expressing Intention or giving your code "deisgnsense" (given intellisense gives you smarts about the raw code)

The test name you have is really testing an implementation detail is correct that bites you in the ass.  Which is fair enough, you often throw these types of tests in.

But its subtly different from expressing whatthe  intent is.   Having an attribute has no direct benefit.  

your test isnt an example of behaviour the code should have.

It's testing an implementation detail that would eventually manifest as broken behaviour.     However your experience is telling you that this thing is easy to get wrong and you want to get direct quick feedback about it if you screw it up.

the test  "must_have_a_service_contract"  would be a intention revealing test

also, I'd tend to move most of the logic out of the test.  Having something you can ask whether a namespace has a servicecontract seems cleaner to me.  The problem when test code gets too much logic is that you start needing a test for your tests.

Assert.IsTrue(  AssemblyValidator.HasNamespace(ASSEMBLY, SERVICE_NAMESPACE))  or some such....

# August 23, 2007 4:23 AM

Derik Whittaker said:

Chris,

This is great, I have forgotten to add those pesky attributes on my WCF stuff as well.  This seems pretty straight forward and simple.  

Cool

Derik

# August 23, 2007 6:07 AM

Christopher Bennage said:

@Keith - I agree with both of your points.  Especially about renaming the test to reveal intent.  Time to refactor my tests!

I think that expressing intent and Design Discovery are just two of the things TDD is about.  Two very important things.  I've come to view TDD as a tool that _may_ be appropriate for solving other problems.  I think that Code Confidence is a different problem from Revealing Intent and Design Discovery; related certainly, but different.

Your post makes a good point.  It's the same issue as chasing 100% code coverage. We should write only as many tests as needed, then stop.

# August 23, 2007 11:52 AM

About Christopher Bennage

Christopher is a software developer and consultant at Blue Spire Consulting, a company he co-founded with Rob Eisenberg in 2006. He is a Christian, a marginal musician, and an armchair philosopher. His interests include programming, liberal education, science, truth, beauty, and a number of deceased British authors (C. S. Lewis, G. K. Chesterton, and most recently Owen Barfield.) He lives in Tallahassee, FL with his wife and three children and still prefers to play as the Night Elves in WarCraft 3. Check out Devlicio.us!

Our Sponsors

Red-Gate!