TDD
Roy has a writeup on why he believes each unit test should only have a single assert. I tried this in the past and didn't like the clutter that it resulted in. The [Test] attribute as well as the method declaration add additional information that we need to parse. If we increase the amount of information that we need to parse past a certain level, our tests begin to feel cluttered and unwieldy. My belief is that a unit test should be testing one single thing. If you need 2-5 asserts to test that one thing than so be it. With that said, I think Roy makes a good argument for 1 assert per unit test. I think I particularly like the idea for those just getting started with TDD and unit testing.
tags: tdd, unit testing, agile
There is a small subset of tests that should hit the database. These include any logic that involves complex queries or where clauses that you’re unsure of and/or complicated save operations involving things that make you uncertain.
The remaining logic within your application most likely doesn't need to hit the database for testing purposes. The more tests that hit the database the slower the test suite is to run. Personally I want my tests to run as fast as possible and to hit the database the least number of times as possible.
That certainly isn't to say tests should never hit the database, just that it should be the exception not the rule.
One of the things that I love about the blogosphere is that it allows everyone to make up new definitions for established practices. As a perfect example have a look at John Wood’s “The Inefficiency of Test Driven Development”.
So what does this have to do with Test Driven Development? Effectively, with only a little hint, I'm determining the requirements based on the reaction to the tests. The tests are driving my efforts to meet her requirements. And this is actually a lot like how TDD works.
With all due respect to John this has absolutely and positively nothing to do with test driven development. If your trying to use TDD to gather your requirements its no wonder your not a fan. Test driven development is not a requirements gathering tool. Believe it or not the people who started the whole agile movement recognized what John is talking about. They recognized that the interactions between people was extremely important. They recognized that the business experts should be a core member of the team and that the interactions between the business experts and programmers was of crucial importance. They even put it at the top of their list of things to value:
Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan
How is it that we’ve fallen so far from what agile and test driven development are about? Perhaps its the fact that the name doesn’t really suite. Perhaps people take it literally and assume that test driven development means that you shouldn’t talk with anyone, just let your tests drive all aspects of your development. Instead of having business prioritize and develop stories we should just dive right into the test driven development process and have the test drive everything. Forget having a vision, just start coding and let the requirements show themselves.
Anyway since I don’t think the point of John’s post was to redefine TDD as a requirements gathering tool I think I’ll stop there. Before I sign off though let me remind you that TDD is about design. It’s not about gathering requirements, its not about defining a contract of intended behaviour, its about following a process that forces you to think about the design of your software every step of the way. If you don’t value design don’t do TDD. If you think TDD is a requirements tool don’t use TDD.
A couple days ago I wrote about how TDD and Unit Testing are NOT the same thing. Today I had the wonderful pleasure of going back and writing unit tests for some existing code that was not developed using TDD. I’d love to point the blame directly at the person who was responsible for such a terrible thing (untested code) but I’m not real big on pointing a finger at myself.
To be fair to myself the code was UI code and was written when I first started at my new gig. I hadn’t done much WinForms programming at that point and had done zero TDD with WinForms. Thankfully I’ve recently seen the light regarding how to “do TDD” with a WinForms UI. Not so thankfully those UI elements that I had written way back when needed to be refactored as part of our migration to MVP and CAB. Since much of the logic was already written we had the pleasure of cranking out unit tests. Frankly writing unit tests kind of sucks. Doing TDD and watching the design of something evolve through tests is much more fun and engaging then cranking out unit tests for stuff that is already in existence. Rather then copying over all the code and writing unit tests on top of that logic we ended up recoding much of the logic in a TDD fashion. At times we cheated and stole the blocks of logic necessary to get a test to pass, and at times we just wrote unit tests. When we were doing TDD things were more fun.
If you want to have more fun use TDD. If you want to be bored write unit tests. 
Is it just me or is everyone claiming to do TDD these days? I think somewhere along the line the definition of TDD got lost. I’ve come across numerous blog posts, comments, and mailing lists where someone was starting to “implement Agile” by doing TDD on their project. Of course since they weren’t yet “doing” Agile they were following the tried and true practice known as Big Design Up Front (BDUF). They were planning out all the details of their application, creating beautiful UML diagrams, and writing big old requirement documents to specify how all the pieces of the system would fit together. Once they had all the details of the application defined they created their classes and finally begun using test driven development to test their objects. As they built up the objects within the application they had the nice tests produced as a result of “test driven development” and thus they were doing Agile!
Test driven development is NOT the same thing as Unit testing! Test driven development is about design. If you’re designing your entire application before writing a line of code your not doing TDD. If you’re writing your classes before writing your tests your not doing TDD. If you’re generating test code using the cool new features in VS 2005 your not doing TDD. TDD and Unit testing are not the same thing.
Unit testing is a good first step on the way to doing test driven development but it is not the same thing. When writing unit tests developers often times have the entire object which they’re unit testing coded up. Unit tests are not being used to drive the design of the object, they’re merely being used to ensure that it acts and behaves as they expect.
It’s important to remember that TDD is about design. It is not an synonym for “unit testing”.
Uncle Bob has a nice little rant on why he’s not very fond of
Microsoft’s re-definition of TDD. It’s interesting that they’ve made “red, green, refactor” into a 15 step process. What’s even more interesting is that they’re calling that 15 step process TDD.
Today as I was reviewing Enterprise Library for .NET 2.0 I noticed a nice little trick they were using to write their unit tests for both NUnit and VS UT (what’s the official name?):
#if
!NUNIT
using Microsoft.VisualStudio.TestTools.UnitTesting;
#else
using NUnit.Framework;
using TestClass = NUnit.Framework.
TestFixtureAttribute;
using TestInitialize = NUnit.Framework.
SetUpAttribute;
using TestCleanup = NUnit.Framework.
TearDownAttribute;
using TestMethod = NUnit.Framework.
TestAttribute;
#endif
Cool! 
Micah Martin and
David Chelimsky of ObjectMentor fame are having a Mock
Off.
Micah likes hand crafted mocks and
David likes using mock
frameworks.
Their Mock Off involves each of them using the others
technique for 3 full days. During their mock off Micah will be
forced to use a mock framework and David will be forced to write hand
crafted mocks.
I'm interested in the result of their mock off. I've been using
hand crafted mocks but have been investigating several mock frameworks
(NMock, NUnit.Mocks, & Rhino Mocks). I think both mock
frameworks and hand crafted mocks have their advantages. Hand
crafted mocks provide you with the ultimate flexibility, while mock
frameworks make it quick and easy to create mocks for testing
objects.
I suppose a more appropriate title for my post would have been "to Mock
framework or not, that is the question", since I think any well
designed application will need mock objects for testing in some
fashion.
Do you use a mock framework? If so, why? If not, why not?
Tonight as I was working on some enhancements to the base framework that I'm using on a couple projects I noticed that the design was kinda...well...terrible. Rather then take a nice phased approach to refactoring the particular classes that were rather messy I did a mass refactoring. About half way through it I stopped and wondered....“what in the world am I doing?” Since I was so far into it I decided to try and complete the refactoring, if I had failed I would have completely backed out and started over using a phased approach. After a couple red bars, and a couple additional refactorings I was seeing all GREEN! Wow, that was one of the less intelligent mass refactorings I'd ever tried, thank goodness I had a full suite of unit tests to validate that I didn't screw something up along the way.
Roy had a bit of an
epiphany while reading
TDD in .NET. You can find the outcome in his most excellent article on using
Enterprise Services to simplify Test Driven Development (TDD) with a database.
In Part 2 of Automating Unit Tests with a Base Class I provided a set of example tests for CRUD operations. Although the logic is correct the implementation...kinda....well....sucks! The main problem is that many of the tests are dependent on functionality that is not directly being tested within the test method. As an example let's look at the CanBeRead() test...
1 public void CanBeRead() {
2
3 Customer savedCustomer = new Customer();
4 // ...set properties
5
6 Assert.IsTrue(savedCustomer.Save());
7
8 // read the customer
9 Customer readCustomer = new Customer();
10 readCustomer.Load(savedCustomer.CustomerID);
11
12 // check properties of the loaded object against the saved object
13 Assert.AreEqual(savedCustomer.ContactName, readCustomer.ContactName, "ContactName properties are not equal.");
14 Assert.AreEqual(savedCustomer.ContactTitle, readCustomer.ContactTitle, "ContactTitle properties are not equal.");
15 Assert.AreEqual(savedCustomer.Address, readCustomer.Address, "Address properties are not equal.");
16
17 // check remaining properties as necessary...
18 }
In order to test the “read“ of the object the test first calls the .Save() method on the customer object. If the .Save() method fails we get a failure for that test and will quickly assume our read logic is incorrect. Unfortunately by including the .Save() within the read test we get an inaccurate view into what is causing problems within our application. A better approach is to manually insert the records using a SQL statement. This prevents a failure in the .Save() from crashing our read test and ensures our tests only fail for a single reason.
So why did I present the test this way? Believe it or not I'm actually using code very similar to this in my test projects. Rather then calling INSERT's to place my test data in my database I'm using the .Save() method on my objects. This allows me to quickly test my objects and also makes the base unit test which I'm sure you are all anxiously awaiting easier to implement. Perhaps after I present my solution to automating the unit tests for CRUD operations I can clean the code up and implement a base test class that uses SQL statement to perform the necessary population and removal of test data.
Have I lost all my TDD/Unit Testing “street cred” by coming out of the closet and admitting to this heinous crime? :-(
In Part 2 of Automating Unit Tests with a Base Class I provided a set of example tests for CRUD operations. Although the logic is correct the implementation...kinda....well....sucks! The main problem is that many of the tests are dependent on functionality that is not directly being tested within the test method. As an example let's look at the CanBeRead() test...
1 public void CanBeRead() {
2
3 Customer savedCustomer = new Customer();
4 // ...set properties
5
6 Assert.IsTrue(savedCustomer.Save());
7
8 // read the customer
9 Customer readCustomer = new Customer();
10 readCustomer.Load(savedCustomer.CustomerID);
11
12 // check properties of the loaded object against the saved object
13 Assert.AreEqual(savedCustomer.ContactName, readCustomer.ContactName, "ContactName properties are not equal.");
14 Assert.AreEqual(savedCustomer.ContactTitle, readCustomer.ContactTitle, "ContactTitle properties are not equal.");
15 Assert.AreEqual(savedCustomer.Address, readCustomer.Address, "Address properties are not equal.");
16
17 // check remaining properties as necessary...
18 }
In order to test the “read“ of the object the test first calls the .Save() method on the customer object. If the .Save() method fails we get a failure for that test and will quickly assume our read logic is incorrect. Unfortunately by including the .Save() within the read test we get an inaccurate view into what is causing problems within our application. A better approach is to manually insert the records using a SQL statement. This prevents a failure in the .Save() from crashing our read test and ensures our tests only fail for a single reason.
So why did I present the test this way? Believe it or not I'm actually using code very similar to this in my test projects. Rather then calling INSERT's to place my test data in my database I'm using the .Save() method on my objects. This allows me to quickly test my objects and also makes the base unit test which I'm sure you are all anxiously awaiting easier to implement. Perhaps after I present my solution to automating the unit tests for CRUD operations I can clean the code up and implement a base test class that uses SQL statement to perform the necessary population and removal of test data.
Have I lost all my TDD/Unit Testing “street cred” by coming out of the closet and admitting to this heinous crime? :-(
The last couple of days I've been working on some enhancement to an application that I wrote a little over a year ago. As I begun to make changes I could feel my stress level rising, my confidence dropping, and my programming ego drowning in a pool of doubt. Clearly this application was written before I had embraced test driven development (TDD). I needed help, my ego clearly couldn't take much more....
Red. Green. Refactor.
Red. Green. Refactor.
Ahhh, stress level dropping, confidence rising, ego climbing....thank you Mr. Tdd!
Jimmy Nilsson has put together a nice transcript for a talk he's giving at VSLive on Test Driven Development. He offers a nice overview of TDD and its benefits.
Check it out! (pdf) (web)