03 September 2008

Test Driven Development Best Practices for C#

As I have mentioned before, my company has recently started to use the Test Driven Development style of programming. In order to help us write testable code, I came up with this simple list of best practices for making our C# code base more testable. (Some of the links refer to limitations of Rhino Mocks, a mocking framework for C#, but the rules apply more generally as well.)

To maximize the testability of code, follow these rules:
  1. Write the test first, then the code. (PRIME DIRECTIVE!)
    Reason: This ensures that you write testable code and that every line of code gets tests written for it.

  2. Design classes using dependency injection.

  3. Separate UI code from its behavior using Model-View-Controller or Model-View-Presenter.
    Reason: Allows the business logic to be tested while the parts that can't be tested (the UI) is minimized.

  4. Do not write static methods or classes.
    See: Intro to Rhino Mocks (see "Creating Testable Web Applications" section) and Rhino Mocks Limitations
    Reason: Static methods are difficult or impossible to isolate and Rhino Mocks is unable to mock them.

  5. Program off interfaces, not classes.
    Reason: Interfaces can be easily mocked using Rhino Mocks and other mocking frameworks.

  6. Isolate external dependencies.
    Reason: Unresolved external dependencies.

  7. Mark as virtual the methods you intend to mock.
    See: Rhino Mocks Limitations
    Reason: Rhino Mocks is unable to mock non-virtual methods.

3 comments:

Dror Helper said...

Very good article Kevin!

However I'd like to point that although writing code for testability is very important sometimes it's not possible or requires horrible design changes.
Not to mention the fact that it could be downright impossible on legacy systems and when using 3rd party components.

In those cases you might consider using Typemock Isolator as a mocking framework that can do all those and more.

I work at Typemock and we have seen several occasions that not writing static method was not an option or the client didn't want to start adding dependency injection at his code.
In those cases you have two options: Don't use mocks at all (not so good) or use Typemock.

Kevin Albrecht said...

Dror,

Thanks for your comment, it inspired me to look into using Typemock at work as a possible replacement for Rhino Mocks, but so far, we are still using Rhino Mocks. We are also evaluating Moq for our next major project, but all three are still on the table.

Dror Helper said...

Kevin,

I'm glad to hear you're considering Isolator for your product(s) in the future. In case you need any assistance using Typemock Isolator just contact me by email: dror at Typemock.com