Unfortunately the definition of unit test is very fuzzy. One of the most cited definitions is done through the properties the tests should have, which are
- runs fast
- is isolated (no interactions between tests, i.e. run them in any order and always get the same result)
- requires no external configuration
- provides a consistent pass/fail result
It's from Roy Osherove's book, the art of unit testing.
If I were to add a definition, I'd say a unit test asserts against the result of a logical path through a method where you have control over the result of all dependencies involved (fwiw, that's just my definition).
Imagine you have to create a method that checks if a string is valid, and if so does something, if not does something different.
This is how we could write that method if we want it to be unit testable:
public SomeClass(IStringAnalyzer stringAnalyzer, ILogger logger)
this.logger = logger;
this.stringAnalyzer = stringAnalyzer;
public void SomeMethod(string someParameter)
//do something with someParameter
stringAnalyser and logger are dependencies because we want to be able to control what they return (through a stub) and how they are used (through a mock).
This is so you can write a test like this (that has all the nice characteristics that Roy describes in his book):
public void SomeMethod_InvalidParameter_CallsLogger
Rhino.Mocks.MockRepository mockRepository = new Rhino.Mocks.MockRepository();
IStringAnalyzer s = mockRepository.Stub<IStringRepository>();
s.Stub(s => s.IsValid("something, doesnt matter").IgnoreParameters().Return(false);
ILogger l = mockRepository.DynamicMock<ILogger>();
SomeClass someClass = new SomeClass(s, l);
someClass.SomeMethod("What you put here doesnt really matter because the stub will always return false");
l.AssertWasCalled(l => l.Log("Invalid string"));
The benefits are that the "several concerns" are all decoupled and they are very easy to spot when you are doing the test first. You'd see that you would need to leave the logic of StringAnalizer out of the class you are testing because the need for controlling if a string is valid or not would be evident.
That test makes use of an isolation framework (rhino mocks) and I explain what that is here: http://blinkingcaret.wordpress.com/2012/11/20/interaction-testing-fakes-mocks-and-stubs/
Regarding the discussion of TDD really produces better designs all I can say is this: http://blinkingcaret.wordpress.com/2012/10/02/tdd-bdd-add-every-other-method-that-promises-software-quality-here-and-the-tea-tasting-lady/
And this: http://vimeo.com/9270320