Unit Testing: Why Bother?
For some, we're simply preaching to the choir, but that's OK. For others, we understand that it's intuitively hard to see how spending all kinds of time on testing will make us go faster. Why doesn't it just slow us down?
For us, there are a few fundamental reasons. First, by writing unit tests and writing them first, we are able to focus on a single unit at a time. This actually focuses our attention on the business logic at hand and the responsibilities of the class under test and their interactions via the interfaces of any dependent classes. Second, it gives us a quick feedback mechanism. We don't have to build everything and then setup some manual situation and finally see if our code works. We can just right click, select run tests, and see if it works right away. It is so much easier do develop a rhythm (test, code, repeat) this way. Lastly, when we move on to other units, we don't really need to worry much about previously constructed units. We know they are fully covered by tests, so before we checkin, we'll run all tests and see that they all pass.
This all improves the efficiency of our immediate development at hand. However even more important is that when later we're off in other parts of the code, we don't have to worry about introducing problems back into the code we just developed. Over time, we all remember less and less about what the rest of the code is like. A lot of it we haven't developed ourselves either. But that's OK. All of our tests are being run all the time, so our quality stays high and we just keep adding more and more code. Or better yet, when we want to undergo some refactoring, we can have the confidence that our system will still function when all the tests run.
Unit Testing vs. Functional Testing
Unit testing is truly more about testing individual units or classes. We can take liberties with respect to dependent classes by mocking or stubbing them out. We can dive into the code at any layer in the system as a starting point.
Functional testing is more about end-to-end testing. And normally, the system is as production-like as possible. This form of testing is also referred to commonly as acceptance testing or customer testing. Many organizations employ other frameworks (e.g. FitNesse) to run such tests, but NUnit can work well here too. Both forms of testing are important.
Strive to test 1 thing per test method:
A simple unit testing best practice is to keep your tests singular in nature. For each test method, strive to test just one thing. Our translation of this isn't necessarily striving for a single assertion. For example, when you setup the class to test a new method, it's often a good idea to assert the base state. This validates your expectation of the state and provides valuable insight to anyone reading your test at a later date. Then make your method call. And lastly, I'd expect at least 1 assertion to follow, but you may have several, depending on your situation.
Solution Setup:
We originally used a blog post by Mike Roberts to help figure out our solution setup. The short version of how we now setup our Visual Studio solutions is to keep all projects in 1 solution where the solution is alone in the root directory. There is a test project for each project under test. And we set the default namespace in the test project to match that of the project under test.

Frameworks
There are multiple frameworks to drive your unit tests from. Here are some of the pros and cons:
NAnt: NAnt is a command line tool, so it's not usually the most convenient to use when you're coding away inside Visual Studio. However, having NAnt scrips are critical for your project's success. This is what will enable your build machine to run all the tests regularly. Another common best practice is to have CruiseControl.NET detect checkins to your source control and then automatically run your NAnt scripts and all your NUnit tests as a form of "continuous integration".

NUnit GUI: The biggest pro we see with this UI is the green bar. It's so satisfying. But the downside it that it takes a couple steps to setup everytime you want to run a test. You need to build and then select "Test With..." and "NUnit GUI". Once the GUI is up you can run all tests or various subsets, including a single test method.
TestDriven.net: This is a winner with us. The downside is no green bar, but you can do things like just right click on the test method you just changed and select "Run Test(s)". There are some little tricks when working with multiple projects and multiple test projects, but it really enables flow to your test driven development.

NUnit Fundamentals
TestFixtures and Tests
NUnit works off of class and method attributes. This means you just have to mark a class as a [TestFixture] (and make sure it's public) and there you go. Test methods have [Test] attribute and a public void signature. This is nice too, since you're not required to begin the method name with "Test". We recommend starting the names in general with "Should" and then describe what it "ShouldDo".
SetUp and TearDown
NUnit supports the concept of [SetUp] and [TearDown], 2 more attributes. SetUp is run before each test method in that TestFixture and TearDown is run after each test method. For example, we often put repetitive object construction in SetUp. Through experience we've found that this is highly preferrable to a simple "private MyObject = new MyObject()" type of declaration. First, to ensure common setup for every test, but second, because if the constructor fails the entire test suite (even at the project level) can fail to construct. And this can be very painful to debug.
Basic Assertions
- Assert.AreEqual
- Assert.IsTrue
- Assert.IsFalse
- Assert.IsNotNull
- Assert.IsNull
These are all pretty self explanatory and there are many more, especially in the newest version of NUnit.

Testing Exceptions
NUnit includes another nice little feature for testing that exceptions get thrown is specific cases. This is done with another attribute, [ExpectedException]. So rather than the old school method of:
[Test]
public void ShouldThrowException() {
MyClass obj = new MyClass();
try {
obj.DoSomething("not this");
Assert.Fail("Shouldn't have gotten here");
} catch (MyException) {
// no assertion required; exception caught
}
}
Now it's just:
[Test]
[ExpectedException(typeof(MyException))]
public void ShouldThrowException() {
MyClass obj = new MyClass();
obj.DoSomething("not this");
}
About a couple extensions:
Continued...